New repo structure: includes stm32-metapac, doesn't commit generated files.

This commit is contained in:
Dario Nieuwenhuis 2023-03-20 01:29:54 +01:00
parent f23cd93430
commit a2333b8afb
34 changed files with 1711 additions and 203 deletions

26
.github/workflows/rust.yml vendored Normal file
View File

@ -0,0 +1,26 @@
name: Rust
on:
push:
branches: [main, new-repo-layout]
pull_request:
branches: [main]
merge_group:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
- name: Check fmt
run: cargo fmt -- --check
- name: Build
run: ./d ci

2
.gitignore vendored
View File

@ -1,3 +1,4 @@
/build
/files /files
/sources /sources
/tmp /tmp
@ -6,4 +7,3 @@ transform*.yaml
__pycache__ __pycache__
target/ target/
Cargo.lock

2
.pep8
View File

@ -1,2 +0,0 @@
[pep8]
max_line_length = 255

View File

@ -1,8 +1,6 @@
{ {
"editor.formatOnSave": true, "editor.formatOnSave": true,
"files.watcherExclude": { "[toml]": {
"**/.git/objects/**": true, "editor.formatOnSave": false
"**/.git/subtree-cache/**": true, },
"**/target/**": true
}
} }

730
Cargo.lock generated Normal file
View File

@ -0,0 +1,730 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "anyhow"
version = "1.0.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4"
[[package]]
name = "atty"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
dependencies = [
"hermit-abi 0.1.19",
"libc",
"winapi",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chiptool"
version = "0.1.0"
source = "git+https://github.com/embassy-rs/chiptool?rev=1d9e0a39a6acc291e50cabc4ed617a87f06d5e89#1d9e0a39a6acc291e50cabc4ed617a87f06d5e89"
dependencies = [
"anyhow",
"clap",
"env_logger",
"inflections",
"log",
"proc-macro2",
"quote",
"regex",
"serde",
"serde_yaml 0.8.26",
"svd-parser",
]
[[package]]
name = "clap"
version = "3.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5"
dependencies = [
"atty",
"bitflags",
"clap_derive",
"clap_lex",
"indexmap",
"once_cell",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap_derive"
version = "3.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "crossbeam-channel"
version = "0.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695"
dependencies = [
"autocfg",
"cfg-if",
"crossbeam-utils",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b"
dependencies = [
"cfg-if",
]
[[package]]
name = "either"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
[[package]]
name = "env_logger"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
dependencies = [
"atty",
"humantime",
"log",
"regex",
"termcolor",
]
[[package]]
name = "glob"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "heck"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "hermit-abi"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "indexmap"
version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
]
[[package]]
name = "inflections"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a"
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "libc"
version = "0.2.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
[[package]]
name = "linked-hash-map"
version = "0.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "memoffset"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1"
dependencies = [
"autocfg",
]
[[package]]
name = "num"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606"
dependencies = [
"num-bigint",
"num-complex",
"num-integer",
"num-iter",
"num-rational",
"num-traits",
]
[[package]]
name = "num-bigint"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-complex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
dependencies = [
"num-traits",
]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0"
dependencies = [
"autocfg",
"num-bigint",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [
"hermit-abi 0.2.6",
"libc",
]
[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "os_str_bytes"
version = "6.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quick-xml"
version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd"
dependencies = [
"memchr",
"serde",
]
[[package]]
name = "quote"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rayon"
version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"num_cpus",
]
[[package]]
name = "ref_thread_local"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0d51660a68078997855ba5602f73ab3a5031bd7ad480a9d4c90fbbf04e1fff0"
[[package]]
name = "regex"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "ryu"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.157"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707de5fcf5df2b5788fca98dd7eab490bc2fd9b7ef1404defc462833b83f25ca"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.157"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78997f4555c22a7971214540c4a661291970619afd56de19f77e0de86296e1e5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.2",
]
[[package]]
name = "serde_json"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "serde_yaml"
version = "0.8.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
dependencies = [
"indexmap",
"ryu",
"serde",
"yaml-rust",
]
[[package]]
name = "serde_yaml"
version = "0.9.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f82e6c8c047aa50a7328632d067bcae6ef38772a79e28daf32f735e0e4f3dd10"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]]
name = "stm32-data-gen"
version = "0.1.0"
dependencies = [
"anyhow",
"chiptool",
"glob",
"num",
"quick-xml",
"rayon",
"ref_thread_local",
"regex",
"serde",
"serde_json",
"serde_yaml 0.9.19",
"stm32-data-serde",
]
[[package]]
name = "stm32-data-serde"
version = "0.1.0"
dependencies = [
"itertools",
"rayon",
"serde",
"serde_json",
]
[[package]]
name = "stm32-metapac-gen"
version = "0.1.0"
dependencies = [
"chiptool",
"proc-macro2",
"regex",
"serde",
"serde_json",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "svd-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "697e7645ad9f5311fe3d872d094b135627b1616aea9e1573dddd28ca522579b9"
dependencies = [
"anyhow",
"once_cell",
"rayon",
"regex",
"thiserror",
"xmltree",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59d3276aee1fa0c33612917969b5172b5be2db051232a6e4826f1a1a9191b045"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "termcolor"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [
"winapi-util",
]
[[package]]
name = "textwrap"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]]
name = "thiserror"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.2",
]
[[package]]
name = "unicode-ident"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "unsafe-libyaml"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad2024452afd3874bf539695e04af6732ba06517424dbf958fdb16a01f3bef6c"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xml-rs"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2"
dependencies = [
"bitflags",
]
[[package]]
name = "xmltree"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff8eaee9d17062850f1e6163b509947969242990ee59a35801af437abe041e70"
dependencies = [
"xml-rs",
]
[[package]]
name = "yaml-rust"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
dependencies = [
"linked-hash-map",
]

View File

@ -1,27 +1,12 @@
[package] [workspace]
name = "stm32-data" members = [
version = "0.1.0" "stm32-data-gen",
edition = "2021" "stm32-data-serde",
"stm32-metapac-gen",
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html ]
exclude = [
[features] "build"
default = ["rayon"] ]
rayon = ["dep:rayon"]
[dependencies]
anyhow = "1.0.66"
glob = "0.3.0"
num = "0.4.0"
quick-xml = { version = "0.26.0", features = ["serialize"] }
regex = "1.6.0"
serde = { version = "1.0.147", features = ["derive"] }
serde_yaml = "0.9.14"
chiptool = { git = "https://github.com/embassy-rs/chiptool", rev = "1d9e0a39a6acc291e50cabc4ed617a87f06d5e89" }
serde_json = "1.0.87"
rayon = { version = "1.5.3", optional = true }
stm32-data-serde = { version = "0.1.0", path = "stm32-data-serde" }
ref_thread_local = "0.1.1"
# Optimize for dev experience: shortest "build+run" time after making a small change. # Optimize for dev experience: shortest "build+run" time after making a small change.
[profile.release] [profile.release]

13
d
View File

@ -3,12 +3,6 @@
set -e set -e
cd $(dirname $0) cd $(dirname $0)
die() { echo "$*" 1>&2; exit 1; }
for i in jq wget svd git; do
command -v "$i" &>/dev/null || die "Missing the command line tool '$i'"
done
CMD=$1 CMD=$1
shift shift
@ -41,6 +35,13 @@ case "$CMD" in
fi fi
done done
;; ;;
ci)
[ -d sources ] || ./d download-all
rm -rf build
cargo run --release --bin stm32-data-gen
cargo run --release --bin stm32-metapac-gen
(cd build/stm32-metapac && cargo check --features stm32h755zi-cm7,pac,metadata)
;;
*) *)
echo "unknown command" echo "unknown command"
;; ;;

View File

@ -97,7 +97,7 @@ fieldset/CNTR:
bit_offset: 2 bit_offset: 2
bit_size: 1 bit_size: 1
- name: FSUSP - name: FSUSP
description: "Suspend state enable Device mode Software can set this bit when the SUSP interrupt is received, which is issued when no traffic is received by the USB peripheral for 3 ms. Software can also set this bit when the L1REQ interrupt is received with positive acknowledge sent. As soon as the suspend state is propagated internally all device activity is stopped, USB clock is gated, USB transceiver is set into low power mode and the SUSPRDY bit is set by hardware. In the case that device application wants to purse more aggressive power saving by stopping the USB clock source and by moving the microcontroller to stop mode, as in the case of bus powered device application, it must first wait few cycles to see the SUSPRDY=1 acknowledge the suspend request. This bit is cleared by hardware simultaneous with the WAKEUP flag set. Host mode Software can set this bit when Host application has nothing scheduled for the next frames and wants to enter long term power saving. When set, it stops immediately SOF generation and any other host activity, gates the USB clock and sets the transceiver in low power mode. If any USB transaction is on-going at the time SUSPEN is set, suspend is entered at the end of the current transaction. As soon as suspend state is propagated internally and gets effective the SUSPRDY bit is set. In the case that host application wants to purse more aggressive power saving by stopping the USB clock source and by moving the micro-controller to STOP mode, it must first wait few cycles to see SUSPRDY=1 acknowledge to the suspend request. This bit is cleared by hardware simultaneous with the WAKEUP flag set." description: "Suspend state enable Device mode Software can set this bit when the SUSP interrupt is received, which is issued when no traffic is received by the USB peripheral for 3 ms. Software can also set this bit when the L1REQ interrupt is received with positive acknowledge sent. As soon as the suspend state is propagated internally all device activity is stopped, USB clock is gated, USB transceiver is set into low power mode and the SUSPRDY bit is set by hardware. In the case that device application wants to purse more aggressive power saving by stopping the USB clock source and by moving the microcontroller to stop mode, as in the case of bus powered device application, it must first wait few cycles to see the SUSPRDY=1 acknowledge the suspend request. This bit is cleared by hardware simultaneous with the WAKEUP flag set. Host mode Software can set this bit when Host application has nothing scheduled for the next frames and wants to enter long term power saving. When set, it stops immediately SOF generation and any other host activity, gates the USB clock and sets the transceiver in low power mode. If any USB transaction is on-going at the time SUSPEN is set, suspend is entered at the end of the current transaction. As soon as suspend state is propagated internally and gets effective the SUSPRDY bit is set. In the case that host application wants to purse more aggressive power saving by stopping the USB clock source and by moving the micro-controller to STOP mode, it must first wait few cycles to see SUSPRDY=1 acknowledge to the suspend request. This bit is cleared by hardware simultaneous with the WAKEUP flag set."
bit_offset: 3 bit_offset: 3
bit_size: 1 bit_size: 1
- name: RESUME - name: RESUME
@ -171,7 +171,7 @@ fieldset/EPR:
bit_offset: 0 bit_offset: 0
bit_size: 4 bit_size: 4
- name: STAT_TX - name: STAT_TX
description: "Status bits, for transmission transfers Device mode These bits contain the information about the endpoint status, listed in . These bits can be toggled by the software to initialize their value. When the application software writes '0, the value remains unchanged, while writing '1 makes the bit value toggle. Hardware sets the STTX bits to NAK, when a correct transfer has occurred (VTTX=1) corresponding to a IN or SETUP (control only) transaction addressed to this channel/endpoint. It then waits for the software to prepare the next set of data to be transmitted. Double-buffered bulk endpoints implement a special transaction flow control, which controls the status based on buffer availability condition (Refer to endpoints). If the endpoint is defined as Isochronous, its status can only be “VALID” or “DISABLED”. Therefore, the hardware cannot change the status of the channel/endpoint/channel after a successful transaction. If the software sets the STTX bits to 'STALL’ or 'NAK’ for an Isochronous channel/endpoint, the USB peripheral behavior is not defined. These bits are read/write but they can be only toggled by writing '1. Host mode Same as STRX behaviour but for IN transactions (TBC)" description: "Status bits, for transmission transfers Device mode These bits contain the information about the endpoint status, listed in . These bits can be toggled by the software to initialize their value. When the application software writes '0, the value remains unchanged, while writing '1 makes the bit value toggle. Hardware sets the STTX bits to NAK, when a correct transfer has occurred (VTTX=1) corresponding to a IN or SETUP (control only) transaction addressed to this channel/endpoint. It then waits for the software to prepare the next set of data to be transmitted. Double-buffered bulk endpoints implement a special transaction flow control, which controls the status based on buffer availability condition (Refer to endpoints). If the endpoint is defined as Isochronous, its status can only be VALID or DISABLED. Therefore, the hardware cannot change the status of the channel/endpoint/channel after a successful transaction. If the software sets the STTX bits to STALL or NAK for an Isochronous channel/endpoint, the USB peripheral behavior is not defined. These bits are read/write but they can be only toggled by writing '1. Host mode Same as STRX behaviour but for IN transactions (TBC)"
bit_offset: 4 bit_offset: 4
bit_size: 2 bit_size: 2
enum: STAT enum: STAT
@ -184,11 +184,11 @@ fieldset/EPR:
bit_offset: 7 bit_offset: 7
bit_size: 1 bit_size: 1
- name: EP_KIND - name: EP_KIND
description: "endpoint/channel kind The meaning of this bit depends on the endpoint/channel type configured by the EP_TYPE bits. summarizes the different meanings. DBL_BUF: This bit is set by the software to enable the double-buffering feature for this bulk endpoint. The usage of double-buffered bulk endpoints is explained in Double-buffered endpoints. STATUS_OUT: This bit is set by the software to indicate that a status out transaction is expected: in this case all OUT transactions containing more than zero data bytes are answered 'STALL’ instead of 'ACK’. This bit may be used to improve the robustness of the application to protocol errors during control transfers and its usage is intended for control endpoints only. When STATUS_OUT is reset, OUT transactions can have any number of bytes, as required." description: "endpoint/channel kind The meaning of this bit depends on the endpoint/channel type configured by the EP_TYPE bits. summarizes the different meanings. DBL_BUF: This bit is set by the software to enable the double-buffering feature for this bulk endpoint. The usage of double-buffered bulk endpoints is explained in Double-buffered endpoints. STATUS_OUT: This bit is set by the software to indicate that a status out transaction is expected: in this case all OUT transactions containing more than zero data bytes are answered STALL instead of ACK. This bit may be used to improve the robustness of the application to protocol errors during control transfers and its usage is intended for control endpoints only. When STATUS_OUT is reset, OUT transactions can have any number of bytes, as required."
bit_offset: 8 bit_offset: 8
bit_size: 1 bit_size: 1
- name: EP_TYPE - name: EP_TYPE
description: "USB type of transaction These bits configure the behavior of this endpoint/channel as described in endpoint/channel type encoding on page 2001. Channel0/Endpoint0 must always be a control endpoint/channel and each USB function must have at least one control endpoint/channel which has address 0, but there may be other control channels/endpoints if required. Only control channels/endpoints handle SETUP transactions, which are ignored by endpoints of other kinds. SETUP transactions cannot be answered with NAK or STALL. If a control endpoint/channel is defined as NAK, the USB peripheral will not answer, simulating a receive error, in the receive direction when a SETUP transaction is received. If the control endpoint/channel is defined as STALL in the receive direction, then the SETUP packet will be accepted anyway, transferring data and issuing the CTR interrupt. The reception of OUT transactions is handled in the normal way, even if the endpoint/channel is a control one. Bulk and interrupt endpoints have very similar behavior and they differ only in the special feature available using the EPKIND configuration bit. The usage of Isochronous channels/endpoints is explained in transfers" description: "USB type of transaction These bits configure the behavior of this endpoint/channel as described in endpoint/channel type encoding on page 2001. Channel0/Endpoint0 must always be a control endpoint/channel and each USB function must have at least one control endpoint/channel which has address 0, but there may be other control channels/endpoints if required. Only control channels/endpoints handle SETUP transactions, which are ignored by endpoints of other kinds. SETUP transactions cannot be answered with NAK or STALL. If a control endpoint/channel is defined as NAK, the USB peripheral will not answer, simulating a receive error, in the receive direction when a SETUP transaction is received. If the control endpoint/channel is defined as STALL in the receive direction, then the SETUP packet will be accepted anyway, transferring data and issuing the CTR interrupt. The reception of OUT transactions is handled in the normal way, even if the endpoint/channel is a control one. Bulk and interrupt endpoints have very similar behavior and they differ only in the special feature available using the EPKIND configuration bit. The usage of Isochronous channels/endpoints is explained in transfers"
bit_offset: 9 bit_offset: 9
bit_size: 2 bit_size: 2
enum: EP_TYPE enum: EP_TYPE
@ -197,7 +197,7 @@ fieldset/EPR:
bit_offset: 11 bit_offset: 11
bit_size: 1 bit_size: 1
- name: STAT_RX - name: STAT_RX
description: "Status bits, for reception transfers Device mode These bits contain information about the endpoint status, which are listed in Reception status encoding on page 2000.These bits can be toggled by software to initialize their value. When the application software writes '0, the value remains unchanged, while writing '1 makes the bit value toggle. Hardware sets the STRX bits to NAK when a correct transfer has occurred (VTRX=1) corresponding to a OUT or SETUP (control only) transaction addressed to this endpoint, so the software has the time to elaborate the received data before it acknowledge a new transaction Double-buffered bulk endpoints implement a special transaction flow control, which control the status based upon buffer availability condition (Refer to endpoints). If the endpoint is defined as Isochronous, its status can be only “VALID” or “DISABLED”, so that the hardware cannot change the status of the endpoint after a successful transaction. If the software sets the STRX bits to 'STALL’ or 'NAK’ for an Isochronous endpoint, the USB peripheral behavior is not defined. These bits are read/write but they can be only toggled by writing '1. Host mode These bits are the host application controls to start, retry, or abort host transactions driven by the channel. These bits also contain information about the device answer to the last IN channel transaction and report the current status of the channel according to the following STRX table of states: -\tDISABLE DISABLE value is reported in case of ACK acknowledge is received on a single-buffer channel. When in DISABLE state the channel is unused or not active waiting for application to restart it by writing VALID. Application can reset a VALID channel to DISABLE to abort a transaction. In this case the transaction is immediately removed from the Host execution list. If the aborted transaction was already under execution it will be regularly terminated on the USB but the relative VTRX interrupt is not generated. -\tVALID An Host channel is actively trying to submit USB transaction to device only when in VALID state.VALID state can be set by software or automatically by hardware on a NAKED channel at the start of a new frame. When set to VALID, an host channel enters the host execution queue and waits permission from the Host Frame Schedure to submit its configured transaction. VALID value is also reported in case of ACK acknowledge is received on a double-buffered channel. In this case the channel remains active on the alternate buffer while application needs to read the current buffer and toggle DTOGTX. In case software is late in reading and the alternate buffer is not ready, the host channel is automatically suspended transparently to the application. The suspended double buffered channel will be re-activated as soon as delay is recovered and DTOGTX is toggled. - NAK NAK value is reported in case of NAK acknowledge received. When in NAK state the channel is suspended and does not try to transmit. NAK state is moved to VALID by hardware at the start of the next frame, or software can change it to immediately retry transmission by writing it to VALID, or can disable it and abort the transaction by writing DISABLE - STALL STALL value is reported in case of STALL acknowledge received. When in STALL state the channel behaves as disabled. Application should not retry transmission but reset the USB and re-enumerate." description: "Status bits, for reception transfers Device mode These bits contain information about the endpoint status, which are listed in Reception status encoding on page 2000.These bits can be toggled by software to initialize their value. When the application software writes '0, the value remains unchanged, while writing '1 makes the bit value toggle. Hardware sets the STRX bits to NAK when a correct transfer has occurred (VTRX=1) corresponding to a OUT or SETUP (control only) transaction addressed to this endpoint, so the software has the time to elaborate the received data before it acknowledge a new transaction Double-buffered bulk endpoints implement a special transaction flow control, which control the status based upon buffer availability condition (Refer to endpoints). If the endpoint is defined as Isochronous, its status can be only VALID or DISABLED, so that the hardware cannot change the status of the endpoint after a successful transaction. If the software sets the STRX bits to 'STALL or 'NAK for an Isochronous endpoint, the USB peripheral behavior is not defined. These bits are read/write but they can be only toggled by writing '1. Host mode These bits are the host application controls to start, retry, or abort host transactions driven by the channel. These bits also contain information about the device answer to the last IN channel transaction and report the current status of the channel according to the following STRX table of states: -\tDISABLE DISABLE value is reported in case of ACK acknowledge is received on a single-buffer channel. When in DISABLE state the channel is unused or not active waiting for application to restart it by writing VALID. Application can reset a VALID channel to DISABLE to abort a transaction. In this case the transaction is immediately removed from the Host execution list. If the aborted transaction was already under execution it will be regularly terminated on the USB but the relative VTRX interrupt is not generated. -\tVALID An Host channel is actively trying to submit USB transaction to device only when in VALID state.VALID state can be set by software or automatically by hardware on a NAKED channel at the start of a new frame. When set to VALID, an host channel enters the host execution queue and waits permission from the Host Frame Schedure to submit its configured transaction. VALID value is also reported in case of ACK acknowledge is received on a double-buffered channel. In this case the channel remains active on the alternate buffer while application needs to read the current buffer and toggle DTOGTX. In case software is late in reading and the alternate buffer is not ready, the host channel is automatically suspended transparently to the application. The suspended double buffered channel will be re-activated as soon as delay is recovered and DTOGTX is toggled. - NAK NAK value is reported in case of NAK acknowledge received. When in NAK state the channel is suspended and does not try to transmit. NAK state is moved to VALID by hardware at the start of the next frame, or software can change it to immediately retry transmission by writing it to VALID, or can disable it and abort the transaction by writing DISABLE - STALL STALL value is reported in case of STALL acknowledge received. When in STALL state the channel behaves as disabled. Application should not retry transmission but reset the USB and re-enumerate."
bit_offset: 12 bit_offset: 12
bit_size: 2 bit_size: 2
enum: STAT enum: STAT
@ -218,7 +218,7 @@ fieldset/EPR:
bit_offset: 23 bit_offset: 23
bit_size: 1 bit_size: 1
- name: LS_EP - name: LS_EP
description: Low speed endpoint – Host with HUB only Host mode This bit is set by the software to send an LS transaction to the corresponding endpoint. description: Low speed endpoint Host with HUB only Host mode This bit is set by the software to send an LS transaction to the corresponding endpoint.
bit_offset: 24 bit_offset: 24
bit_size: 1 bit_size: 1
- name: ERR_TX - name: ERR_TX
@ -269,11 +269,11 @@ fieldset/ISTR:
bit_offset: 7 bit_offset: 7
bit_size: 1 bit_size: 1
- name: ESOF - name: ESOF
description: "Expected start of frame This bit is set by the hardware when an SOF packet is expected but not received. The host sends an SOF packet each 1 ms, but if the device does not receive it properly, the Suspend Timer issues this interrupt. If three consecutive ESOF interrupts are generated (i.e. three SOF packets are lost) without any traffic occurring in between, a SUSP interrupt is generated. This bit is set even when the missing SOF packets occur while the Suspend Timer is not yet locked. This bit is read/write but only '0 can be written and writing '1 has no effect." description: "Expected start of frame This bit is set by the hardware when an SOF packet is expected but not received. The host sends an SOF packet each 1 ms, but if the device does not receive it properly, the Suspend Timer issues this interrupt. If three consecutive ESOF interrupts are generated (i.e. three SOF packets are lost) without any traffic occurring in between, a SUSP interrupt is generated. This bit is set even when the missing SOF packets occur while the Suspend Timer is not yet locked. This bit is read/write but only '0 can be written and writing '1 has no effect."
bit_offset: 8 bit_offset: 8
bit_size: 1 bit_size: 1
- name: SOF - name: SOF
description: "Start of frame This bit signals the beginning of a new USB frame and it is set when a SOF packet arrives through the USB bus. The interrupt service routine may monitor the SOF events to have a 1 ms synchronization event to the USB host and to safely read the USB_FNR register which is updated at the SOF packet reception (this could be useful for isochronous applications). This bit is read/write but only '0 can be written and writing '1 has no effect." description: "Start of frame This bit signals the beginning of a new USB frame and it is set when a SOF packet arrives through the USB bus. The interrupt service routine may monitor the SOF events to have a 1 ms synchronization event to the USB host and to safely read the USB_FNR register which is updated at the SOF packet reception (this could be useful for isochronous applications). This bit is read/write but only '0 can be written and writing '1 has no effect."
bit_offset: 9 bit_offset: 9
bit_size: 1 bit_size: 1
- name: RESET - name: RESET
@ -281,7 +281,7 @@ fieldset/ISTR:
bit_offset: 10 bit_offset: 10
bit_size: 1 bit_size: 1
- name: SUSP - name: SUSP
description: "Suspend mode request This bit is set by the hardware when no traffic has been received for 3 ms, indicating a suspend mode request from the USB bus. The suspend condition check is enabled immediately after any USB reset and it is disabled by the hardware when the suspend mode is active (SUSPEN=1) until the end of resume sequence. This bit is read/write but only '0 can be written and writing '1 has no effect." description: "Suspend mode request This bit is set by the hardware when no traffic has been received for 3 ms, indicating a suspend mode request from the USB bus. The suspend condition check is enabled immediately after any USB reset and it is disabled by the hardware when the suspend mode is active (SUSPEN=1) until the end of resume sequence. This bit is read/write but only '0 can be written and writing '1 has no effect."
bit_offset: 11 bit_offset: 11
bit_size: 1 bit_size: 1
- name: WKUP - name: WKUP

View File

@ -1,40 +0,0 @@
#!/usr/bin/env bash
echo "Usage: ./extract.sh all|<board_name> <peripheral>"
board=$1
peri=$2
mkdir -p regs/$peri
cargo build --release --manifest-path ../../svd4rust/Cargo.toml
transform="transform.yaml"
if [ -f "transform-$peri.yaml" ];
then
transform="transform-$peri.yaml"
fi
query="sources/svd";
if [ $board != "all" ];
then
query="sources/svd/stm32$board*.svd"
fi
for f in `ls $query`; do
f=${f##*/}
f=${f#"stm32"}
f=${f%".svd"}
echo -n processing $f ...
RUST_LOG=info ../../svd4rust/target/release/svd4rust extract-peripheral --svd sources/svd/stm32$f.svd --transform $transform --peripheral $peri > regs/$peri/$f.yaml 2> regs/$peri/$f.yaml.out
if [ $? -ne 0 ]; then
mv regs/$peri/$f.yaml.out regs/$peri/$f.err
rm regs/$peri/$f.yaml
echo FAIL
else
rm regs/$peri/$f.yaml.out
echo OK
fi
done

View File

@ -1,3 +0,0 @@
#!/bin/bash
jq -r ".MCUs[] | select(.RPN == \"$1\") | .files[].file_id" sources/mcufinder/mcus.json

View File

@ -1,11 +0,0 @@
#!/bin/bash
#jq ".MCUs[] | select(.RPN == \"$1\") | .files[].file_id" sources/mcufinder/mcus.json
files=$(./files_for.sh $1)
#echo $files
for candidate in $files
do
jq -e ".Files[] | select(.id_file == \"$candidate\") | select(.type == \"Reference manual\")" ./sources/mcufinder/files.json
done

View File

@ -1,92 +0,0 @@
use std::collections::HashMap;
use crate::regex;
#[derive(Debug)]
pub struct PeripheralToClock(
HashMap<(String, String, String), HashMap<String, stm32_data_serde::chip::core::peripheral::Rcc>>,
);
impl PeripheralToClock {
pub fn parse() -> anyhow::Result<Self> {
let mut peripheral_to_clock = HashMap::new();
for f in glob::glob("data/registers/rcc_*")? {
let f = f?;
let ff = f
.file_name()
.unwrap()
.to_string_lossy()
.strip_prefix("rcc_")
.unwrap()
.strip_suffix(".yaml")
.unwrap()
.to_string();
let mut family_clocks = HashMap::new();
let y: chiptool::ir::IR = serde_yaml::from_str(&std::fs::read_to_string(f)?)?;
for (reg, body) in &y.fieldsets {
let key = format!("fieldset/{reg}");
if let Some(m) = regex!(r"^fieldset/((A[PH]B\d?)|GPIO)[LH]?ENR\d?$").captures(&key) {
let clock = m.get(1).unwrap().as_str();
let clock = match clock {
"AHB" => "AHB1",
"APB" => "APB1",
clock => clock,
};
for field in &body.fields {
if let Some(peri) = field.name.strip_suffix("EN") {
// Timers are a bit special, they may have a x2 freq
let peri_clock = {
if regex!(r"^TIM\d+$").is_match(peri) {
format!("{clock}_TIM")
} else {
clock.to_string()
}
};
let mut reset = None;
if let Some(rstr) = y.fieldsets.get(&reg.replace("ENR", "RSTR")) {
if let Some(_field) =
rstr.fields.iter().find(|field| field.name == format!("{peri}RST"))
{
reset = Some(stm32_data_serde::chip::core::peripheral::rcc::Reset {
register: reg.replace("ENR", "RSTR"),
field: format!("{peri}RST"),
});
}
}
let res = stm32_data_serde::chip::core::peripheral::Rcc {
clock: peri_clock,
enable: stm32_data_serde::chip::core::peripheral::rcc::Enable {
register: reg.clone(),
field: field.name.clone(),
},
reset,
};
family_clocks.insert(peri.to_string(), res);
}
}
}
}
peripheral_to_clock.insert(("rcc".to_string(), ff, "RCC".to_string()), family_clocks);
}
Ok(Self(peripheral_to_clock))
}
pub fn match_peri_clock(
&self,
rcc_block: (String, String, String),
peri_name: &str,
) -> Option<&stm32_data_serde::chip::core::peripheral::Rcc> {
let clocks = self.0.get(&rcc_block)?;
if let Some(res) = clocks.get(peri_name) {
Some(res)
} else if let Some(peri_name) = peri_name.strip_suffix('1') {
self.match_peri_clock(rcc_block, peri_name)
} else {
None
}
}
}

24
stm32-data-gen/Cargo.toml Normal file
View File

@ -0,0 +1,24 @@
[package]
name = "stm32-data-gen"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["rayon"]
rayon = ["dep:rayon"]
[dependencies]
anyhow = "1.0.70"
glob = "0.3.1"
num = "0.4.0"
quick-xml = { version = "0.26.0", features = ["serialize"] }
regex = "1.7.1"
serde = { version = "1.0.157", features = ["derive"] }
serde_yaml = "0.9.19"
chiptool = { git = "https://github.com/embassy-rs/chiptool", rev = "1d9e0a39a6acc291e50cabc4ed617a87f06d5e89" }
serde_json = "1.0.94"
rayon = { version = "1.7.0", optional = true }
stm32-data-serde = { version = "0.1.0", path = "../stm32-data-serde" }
ref_thread_local = "0.1.1"

View File

@ -1090,7 +1090,7 @@ fn process_chip(
cleaned cleaned
}; };
std::fs::write(format!("data/chips/{chip_name}.json"), dump)?; std::fs::write(format!("build/data/chips/{chip_name}.json"), dump)?;
Ok(()) Ok(())
} }
@ -1106,7 +1106,7 @@ pub fn dump_all_chips(
memories: memory::Memories, memories: memory::Memories,
docs: docs::Docs, docs: docs::Docs,
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
std::fs::create_dir_all("data/chips")?; std::fs::create_dir_all("build/data/chips")?;
#[cfg(feature = "rayon")] #[cfg(feature = "rayon")]
{ {

View File

@ -50,7 +50,7 @@ impl HeaderMap {
pub fn parse() -> anyhow::Result<Self> { pub fn parse() -> anyhow::Result<Self> {
let mut res = HashMap::new(); let mut res = HashMap::new();
for (mut header, chips) in for (mut header, chips) in
serde_yaml::from_str::<HashMap<String, String>>(&std::fs::read_to_string("header_map.yaml")?)? serde_yaml::from_str::<HashMap<String, String>>(&std::fs::read_to_string("data/header_map.yaml")?)?
{ {
header.make_ascii_lowercase(); header.make_ascii_lowercase();
for chip in chips.split(',') { for chip in chips.split(',') {

View File

@ -6,6 +6,7 @@ mod header;
mod interrupts; mod interrupts;
mod memory; mod memory;
mod rcc; mod rcc;
mod registers;
#[macro_export] #[macro_export]
macro_rules! regex { macro_rules! regex {
@ -62,6 +63,10 @@ fn main() -> anyhow::Result<()> {
stopwatch.section("Parsing other stuff"); stopwatch.section("Parsing other stuff");
// stopwatch.section("Parsing registers");
let registers = registers::Registers::parse()?;
registers.write()?;
// stopwatch.section("Parsing memories"); // stopwatch.section("Parsing memories");
let memories = memory::Memories::parse()?; let memories = memory::Memories::parse()?;
@ -69,7 +74,7 @@ fn main() -> anyhow::Result<()> {
let chip_interrupts = interrupts::ChipInterrupts::parse()?; let chip_interrupts = interrupts::ChipInterrupts::parse()?;
// stopwatch.section("Parsing RCC registers"); // stopwatch.section("Parsing RCC registers");
let peripheral_to_clock = rcc::PeripheralToClock::parse()?; let peripheral_to_clock = rcc::PeripheralToClock::parse(&registers)?;
// stopwatch.section("Parsing docs"); // stopwatch.section("Parsing docs");
let docs = docs::Docs::parse()?; let docs = docs::Docs::parse()?;

88
stm32-data-gen/src/rcc.rs Normal file
View File

@ -0,0 +1,88 @@
use std::collections::HashMap;
use crate::regex;
use crate::registers::Registers;
#[derive(Debug)]
pub struct PeripheralToClock(
HashMap<(String, String, String), HashMap<String, stm32_data_serde::chip::core::peripheral::Rcc>>,
);
impl PeripheralToClock {
pub fn parse(registers: &Registers) -> anyhow::Result<Self> {
let mut peripheral_to_clock = HashMap::new();
for (rcc_name, ir) in &registers.registers {
if let Some(rcc_name) = rcc_name.strip_prefix("rcc_") {
let mut family_clocks = HashMap::new();
for (reg, body) in &ir.fieldsets {
let key = format!("fieldset/{reg}");
if let Some(m) = regex!(r"^fieldset/((A[PH]B\d?)|GPIO)[LH]?ENR\d?$").captures(&key) {
let clock = m.get(1).unwrap().as_str();
let clock = match clock {
"AHB" => "AHB1",
"APB" => "APB1",
clock => clock,
};
for field in &body.fields {
if let Some(peri) = field.name.strip_suffix("EN") {
// Timers are a bit special, they may have a x2 freq
let peri_clock = {
if regex!(r"^TIM\d+$").is_match(peri) {
format!("{clock}_TIM")
} else {
clock.to_string()
}
};
let mut reset = None;
if let Some(rstr) = ir.fieldsets.get(&reg.replace("ENR", "RSTR")) {
if let Some(_field) =
rstr.fields.iter().find(|field| field.name == format!("{peri}RST"))
{
reset = Some(stm32_data_serde::chip::core::peripheral::rcc::Reset {
register: reg.replace("ENR", "RSTR"),
field: format!("{peri}RST"),
});
}
}
let res = stm32_data_serde::chip::core::peripheral::Rcc {
clock: peri_clock,
enable: stm32_data_serde::chip::core::peripheral::rcc::Enable {
register: reg.clone(),
field: field.name.clone(),
},
reset,
};
family_clocks.insert(peri.to_string(), res);
}
}
}
}
peripheral_to_clock.insert(
("rcc".to_string(), rcc_name.to_string(), "RCC".to_string()),
family_clocks,
);
}
}
Ok(Self(peripheral_to_clock))
}
pub fn match_peri_clock(
&self,
rcc_block: (String, String, String),
peri_name: &str,
) -> Option<&stm32_data_serde::chip::core::peripheral::Rcc> {
let clocks = self.0.get(&rcc_block)?;
if let Some(res) = clocks.get(peri_name) {
Some(res)
} else if let Some(peri_name) = peri_name.strip_suffix('1') {
self.match_peri_clock(rcc_block, peri_name)
} else {
None
}
}
}

View File

@ -0,0 +1,40 @@
use std::collections::HashMap;
use anyhow::anyhow;
use chiptool::ir::IR;
pub struct Registers {
pub registers: HashMap<String, IR>,
}
impl Registers {
pub fn parse() -> Result<Self, anyhow::Error> {
let mut registers = HashMap::new();
for f in glob::glob("data/registers/*")? {
let f = f?;
let ff = f
.file_name()
.unwrap()
.to_string_lossy()
.strip_suffix(".yaml")
.unwrap()
.to_string();
let ir: IR = serde_yaml::from_str(&std::fs::read_to_string(&f)?)
.map_err(|e| anyhow!("failed to parse {f:?}: {e:?}"))?;
registers.insert(ff, ir);
}
Ok(Self { registers })
}
pub fn write(&self) -> Result<(), anyhow::Error> {
std::fs::create_dir_all("build/data/registers")?;
for (name, ir) in &self.registers {
let dump = serde_json::to_string_pretty(ir)?;
std::fs::write(format!("build/data/registers/{name}.json"), dump)?;
}
Ok(())
}
}

View File

@ -6,9 +6,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
serde = { version = "1.0.147", features = ["derive"] } serde = { version = "1.0.157", features = ["derive"] }
[dev-dependencies] [dev-dependencies]
itertools = "0.10.5" itertools = "0.10.5"
rayon = "1.5.3" rayon = "1.7.0"
serde_json = "1.0.87" serde_json = "1.0.94"

View File

@ -268,7 +268,7 @@ mod tests {
itertools::assert_equal(normalize(&original), normalize(&reencoded)) itertools::assert_equal(normalize(&original), normalize(&reencoded))
} }
const CHIPS_DIR: &str = "../data/chips/"; const CHIPS_DIR: &str = "../build/data/chips/";
#[test] #[test]
fn test_one() { fn test_one() {

View File

@ -0,0 +1,14 @@
[package]
name = "stm32-metapac-gen"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
[dependencies]
regex = "1.7.1"
chiptool = { git = "https://github.com/embassy-rs/chiptool", rev = "1d9e0a39a6acc291e50cabc4ed617a87f06d5e89" }
serde = { version = "1.0.157", features = [ "derive" ] }
serde_json = "1.0.94"
proc-macro2 = "1.0.52"

View File

@ -0,0 +1,62 @@
[package]
name = "stm32-metapac"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/embassy-rs/stm32-data"
description = "Peripheral Access Crate (PAC) for all STM32 chips, including metadata."
# `cargo publish` is unable to figure out which .rs files are needed due to the include! magic.
include = [
"**/*.rs",
"**/*.x",
"Cargo.toml",
]
[package.metadata.docs.rs]
features = ["stm32h755zi-cm7", "pac", "metadata"]
default-target = "thumbv7em-none-eabihf"
targets = []
[package.metadata.embassy_docs]
features = ["pac", "metadata"]
flavors = [
{ regex_feature = "stm32f0.*", target = "thumbv6m-none-eabi" },
{ regex_feature = "stm32f1.*", target = "thumbv7m-none-eabi" },
{ regex_feature = "stm32f2.*", target = "thumbv7m-none-eabi" },
{ regex_feature = "stm32f3.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32f4.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32f7.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32c0.*", target = "thumbv6m-none-eabi" },
{ regex_feature = "stm32g0.*", target = "thumbv6m-none-eabi" },
{ regex_feature = "stm32g4.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32h7.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32l0.*", target = "thumbv6m-none-eabi" },
{ regex_feature = "stm32l1.*", target = "thumbv7m-none-eabi" },
{ regex_feature = "stm32l4.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32l5.*", target = "thumbv8m.main-none-eabihf" },
{ regex_feature = "stm32u5.*", target = "thumbv8m.main-none-eabihf" },
{ regex_feature = "stm32wb.*", target = "thumbv7em-none-eabi" },
{ regex_feature = "stm32wl.*", target = "thumbv7em-none-eabi" },
]
[dependencies]
cortex-m = "0.7.6"
cortex-m-rt = { version = ">=0.6.15,<0.8", optional = true }
[features]
default = ["pac"]
# Build the actual PAC. Set by default.
# If you just want the metadata, unset it with `default-features = false`.
pac = []
# Build the chip metadata.
# If set, a const `stm32_metapac::METADATA` will be exported, containing all the
# metadata for the currently selected chip.
metadata = []
rt = ["cortex-m-rt/device"]
memory-x = []
# Chip-selection features

View File

@ -0,0 +1,35 @@
use std::env;
use std::path::PathBuf;
fn main() {
let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
let chip_core_name = env::vars_os()
.map(|(a, _)| a.to_string_lossy().to_string())
.find(|x| x.starts_with("CARGO_FEATURE_STM32"))
.expect("No stm32xx Cargo feature enabled")
.strip_prefix("CARGO_FEATURE_")
.unwrap()
.to_ascii_lowercase()
.replace('_', "-");
println!(
"cargo:rustc-link-search={}/src/chips/{}",
crate_dir.display(),
chip_core_name,
);
#[cfg(feature = "memory-x")]
println!(
"cargo:rustc-link-search={}/src/chips/{}/memory_x/",
crate_dir.display(),
chip_core_name
);
println!("cargo:rustc-env=STM32_METAPAC_PAC_PATH=chips/{}/pac.rs", chip_core_name);
println!(
"cargo:rustc-env=STM32_METAPAC_METADATA_PATH=chips/{}/metadata.rs",
chip_core_name
);
println!("cargo:rerun-if-changed=build.rs");
}

View File

@ -0,0 +1,16 @@
#![no_std]
#![allow(non_snake_case)]
#![allow(unused)]
#![allow(non_camel_case_types)]
#![doc(html_no_source)]
pub mod common;
#[cfg(feature = "pac")]
include!(env!("STM32_METAPAC_PAC_PATH"));
#[cfg(feature = "metadata")]
pub mod metadata {
include!("metadata.rs");
include!(env!("STM32_METAPAC_METADATA_PATH"));
}

View File

@ -0,0 +1,106 @@
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Metadata {
pub name: &'static str,
pub family: &'static str,
pub line: &'static str,
pub memory: &'static [MemoryRegion],
pub peripherals: &'static [Peripheral],
pub interrupts: &'static [Interrupt],
pub dma_channels: &'static [DmaChannel],
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct MemoryRegion {
pub name: &'static str,
pub kind: MemoryRegionKind,
pub address: u32,
pub size: u32,
pub settings: Option<FlashSettings>,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct FlashSettings {
pub erase_size: u32,
pub write_size: u32,
pub erase_value: u8,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum MemoryRegionKind {
Flash,
Ram,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Interrupt {
pub name: &'static str,
pub number: u32,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Package {
pub name: &'static str,
pub package: &'static str,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Peripheral {
pub name: &'static str,
pub address: u64,
pub registers: Option<PeripheralRegisters>,
pub rcc: Option<PeripheralRcc>,
pub pins: &'static [PeripheralPin],
pub dma_channels: &'static [PeripheralDmaChannel],
pub interrupts: &'static [PeripheralInterrupt],
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct PeripheralRegisters {
pub kind: &'static str,
pub version: &'static str,
pub block: &'static str,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct PeripheralInterrupt {
pub signal: &'static str,
pub interrupt: &'static str,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct PeripheralRcc {
pub clock: &'static str,
pub enable: Option<PeripheralRccRegister>,
pub reset: Option<PeripheralRccRegister>,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct PeripheralRccRegister {
pub register: &'static str,
pub field: &'static str,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct PeripheralPin {
pub pin: &'static str,
pub signal: &'static str,
pub af: Option<u8>,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct DmaChannel {
pub name: &'static str,
pub dma: &'static str,
pub channel: u32,
pub dmamux: Option<&'static str>,
pub dmamux_channel: Option<u32>,
}
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct PeripheralDmaChannel {
pub signal: &'static str,
pub channel: Option<&'static str>,
pub dmamux: Option<&'static str>,
pub dma: Option<&'static str>,
pub request: Option<u32>,
}

View File

@ -0,0 +1,124 @@
use serde::Deserialize;
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct Chip {
pub name: String,
pub family: String,
pub line: String,
pub cores: Vec<Core>,
pub memory: Vec<MemoryRegion>,
pub packages: Vec<Package>,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct MemoryRegion {
pub name: String,
pub kind: MemoryRegionKind,
pub address: u32,
pub size: u32,
pub settings: Option<FlashSettings>,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct FlashSettings {
pub erase_size: u32,
pub write_size: u32,
pub erase_value: u8,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub enum MemoryRegionKind {
#[serde(rename = "flash")]
Flash,
#[serde(rename = "ram")]
Ram,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct Core {
pub name: String,
pub peripherals: Vec<Peripheral>,
pub interrupts: Vec<Interrupt>,
pub dma_channels: Vec<DmaChannel>,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct Interrupt {
pub name: String,
pub number: u32,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct Package {
pub name: String,
pub package: String,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct Peripheral {
pub name: String,
pub address: u64,
#[serde(default)]
pub registers: Option<PeripheralRegisters>,
#[serde(default)]
pub rcc: Option<PeripheralRcc>,
#[serde(default)]
pub pins: Vec<PeripheralPin>,
#[serde(default)]
pub dma_channels: Vec<PeripheralDmaChannel>,
#[serde(default)]
pub interrupts: Vec<PeripheralInterrupt>,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct PeripheralInterrupt {
pub signal: String,
pub interrupt: String,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct PeripheralRcc {
pub clock: String,
#[serde(default)]
pub enable: Option<PeripheralRccRegister>,
#[serde(default)]
pub reset: Option<PeripheralRccRegister>,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct PeripheralRccRegister {
pub register: String,
pub field: String,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct PeripheralPin {
pub pin: String,
pub signal: String,
pub af: Option<u8>,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize)]
pub struct DmaChannel {
pub name: String,
pub dma: String,
pub channel: u32,
pub dmamux: Option<String>,
pub dmamux_channel: Option<u32>,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Hash)]
pub struct PeripheralDmaChannel {
pub signal: String,
pub channel: Option<String>,
pub dmamux: Option<String>,
pub dma: Option<String>,
pub request: Option<u32>,
}
#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Hash)]
pub struct PeripheralRegisters {
pub kind: String,
pub version: String,
pub block: String,
}

View File

@ -0,0 +1,369 @@
use std::collections::{BTreeMap, HashMap, HashSet};
use std::fmt::{Debug, Write as _};
use std::fs;
use std::fs::File;
use std::io::Write;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use chiptool::generate::CommonModule;
use chiptool::{generate, ir, transform};
use proc_macro2::TokenStream;
use regex::Regex;
mod data;
use data::*;
#[derive(Debug, Eq, PartialEq, Clone)]
struct Metadata<'a> {
name: &'a str,
family: &'a str,
line: &'a str,
memory: &'a [MemoryRegion],
peripherals: &'a [Peripheral],
interrupts: &'a [Interrupt],
dma_channels: &'a [DmaChannel],
}
pub struct Options {
pub chips: Vec<String>,
pub out_dir: PathBuf,
pub data_dir: PathBuf,
}
pub struct Gen {
opts: Options,
all_peripheral_versions: HashSet<(String, String)>,
metadata_dedup: HashMap<String, String>,
}
impl Gen {
pub fn new(opts: Options) -> Self {
Self {
opts,
all_peripheral_versions: HashSet::new(),
metadata_dedup: HashMap::new(),
}
}
fn gen_chip(&mut self, chip_core_name: &str, chip: &Chip, core: &Core, core_index: usize) {
let mut ir = ir::IR::new();
let mut dev = ir::Device {
interrupts: Vec::new(),
peripherals: Vec::new(),
};
let mut peripheral_versions: BTreeMap<String, String> = BTreeMap::new();
let gpio_base = core.peripherals.iter().find(|p| p.name == "GPIOA").unwrap().address as u32;
let gpio_stride = 0x400;
for p in &core.peripherals {
let mut ir_peri = ir::Peripheral {
name: p.name.clone(),
array: None,
base_address: p.address,
block: None,
description: None,
interrupts: HashMap::new(),
};
if let Some(bi) = &p.registers {
if let Some(old_version) = peripheral_versions.insert(bi.kind.clone(), bi.version.clone()) {
if old_version != bi.version {
panic!(
"Peripheral {} has multiple versions: {} and {}",
bi.kind, old_version, bi.version
);
}
}
ir_peri.block = Some(format!("{}::{}", bi.kind, bi.block));
if bi.kind == "gpio" {
assert_eq!(0, (p.address as u32 - gpio_base) % gpio_stride);
}
}
dev.peripherals.push(ir_peri);
}
for irq in &core.interrupts {
dev.interrupts.push(ir::Interrupt {
name: irq.name.clone(),
description: None,
value: irq.number,
});
}
ir.devices.insert("".to_string(), dev);
let mut extra = format!(
"pub fn GPIO(n: usize) -> gpio::Gpio {{
gpio::Gpio(({} + {}*n) as _)
}}",
gpio_base, gpio_stride,
);
for (module, version) in &peripheral_versions {
self.all_peripheral_versions.insert((module.clone(), version.clone()));
write!(
&mut extra,
"#[path=\"../../peripherals/{}_{}.rs\"] pub mod {};\n",
module, version, module
)
.unwrap();
}
write!(&mut extra, "pub const CORE_INDEX: usize = {};\n", core_index).unwrap();
let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap();
let settings = flash.settings.as_ref().unwrap();
write!(&mut extra, "pub const FLASH_BASE: usize = {};\n", flash.address).unwrap();
write!(&mut extra, "pub const FLASH_SIZE: usize = {};\n", flash.size).unwrap();
write!(&mut extra, "pub const ERASE_SIZE: usize = {};\n", settings.erase_size).unwrap();
write!(&mut extra, "pub const WRITE_SIZE: usize = {};\n", settings.write_size).unwrap();
write!(&mut extra, "pub const ERASE_VALUE: u8 = {};\n", settings.erase_value).unwrap();
// Cleanups!
transform::sort::Sort {}.run(&mut ir).unwrap();
transform::Sanitize {}.run(&mut ir).unwrap();
// ==============================
// Setup chip dir
let chip_dir = self
.opts
.out_dir
.join("src/chips")
.join(chip_core_name.to_ascii_lowercase());
fs::create_dir_all(&chip_dir).unwrap();
// ==============================
// generate pac.rs
let data = generate::render(&ir, &gen_opts()).unwrap().to_string();
let data = data.replace("] ", "]\n");
// Remove inner attributes like #![no_std]
let data = Regex::new("# *! *\\[.*\\]").unwrap().replace_all(&data, "");
let mut file = File::create(chip_dir.join("pac.rs")).unwrap();
file.write_all(data.as_bytes()).unwrap();
file.write_all(extra.as_bytes()).unwrap();
let mut device_x = String::new();
for irq in &core.interrupts {
write!(&mut device_x, "PROVIDE({} = DefaultHandler);\n", irq.name).unwrap();
}
// ==============================
// generate metadata.rs
// (peripherals, interrupts, dma_channels) are often equal across multiple chips.
// To reduce bloat, deduplicate them.
let mut data = String::new();
write!(
&mut data,
"
const PERIPHERALS: &'static [Peripheral] = {};
const INTERRUPTS: &'static [Interrupt] = {};
const DMA_CHANNELS: &'static [DmaChannel] = {};
",
stringify(&core.peripherals),
stringify(&core.interrupts),
stringify(&core.dma_channels),
)
.unwrap();
let out_dir = self.opts.out_dir.clone();
let n = self.metadata_dedup.len();
let deduped_file = self.metadata_dedup.entry(data.clone()).or_insert_with(|| {
let file = format!("metadata_{:04}.rs", n);
let path = out_dir.join("src/chips").join(&file);
fs::write(path, data).unwrap();
file
});
let data = format!(
"include!(\"../{}\");
pub const METADATA: Metadata = Metadata {{
name: {:?},
family: {:?},
line: {:?},
memory: {},
peripherals: PERIPHERALS,
interrupts: INTERRUPTS,
dma_channels: DMA_CHANNELS,
}};",
deduped_file,
&chip.name,
&chip.family,
&chip.line,
stringify(&chip.memory),
);
let mut file = File::create(chip_dir.join("metadata.rs")).unwrap();
file.write_all(data.as_bytes()).unwrap();
// ==============================
// generate device.x
File::create(chip_dir.join("device.x"))
.unwrap()
.write_all(device_x.as_bytes())
.unwrap();
// ==============================
// generate default memory.x
gen_memory_x(&chip_dir, &chip);
}
fn load_chip(&mut self, name: &str) -> Chip {
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));
serde_json::from_slice(&chip).unwrap()
}
pub fn gen(&mut self) {
fs::create_dir_all(self.opts.out_dir.join("src/peripherals")).unwrap();
fs::create_dir_all(self.opts.out_dir.join("src/chips")).unwrap();
let mut chip_core_names: Vec<String> = Vec::new();
for chip_name in &self.opts.chips.clone() {
println!("Generating {}...", chip_name);
let mut chip = self.load_chip(chip_name);
// Cleanup
for core in &mut chip.cores {
for irq in &mut core.interrupts {
irq.name = irq.name.to_ascii_uppercase();
}
for p in &mut core.peripherals {
for irq in &mut p.interrupts {
irq.interrupt = irq.interrupt.to_ascii_uppercase();
}
}
}
// Generate
for (core_index, core) in chip.cores.iter().enumerate() {
let chip_core_name = match chip.cores.len() {
1 => chip_name.clone(),
_ => format!("{}-{}", chip_name, core.name),
};
chip_core_names.push(chip_core_name.clone());
self.gen_chip(&chip_core_name, &chip, core, core_index)
}
}
for (module, version) in &self.all_peripheral_versions {
println!("loading {} {}", module, version);
let regs_path = Path::new(&self.opts.data_dir)
.join("registers")
.join(&format!("{}_{}.json", module, version));
let mut ir: ir::IR = serde_json::from_reader(File::open(regs_path).unwrap()).unwrap();
transform::expand_extends::ExpandExtends {}.run(&mut ir).unwrap();
transform::map_names(&mut ir, |k, s| match k {
transform::NameKind::Block => *s = format!("{}", s),
transform::NameKind::Fieldset => *s = format!("regs::{}", s),
transform::NameKind::Enum => *s = format!("vals::{}", s),
_ => {}
});
transform::sort::Sort {}.run(&mut ir).unwrap();
transform::Sanitize {}.run(&mut ir).unwrap();
let items = generate::render(&ir, &gen_opts()).unwrap();
let mut file = File::create(
self.opts
.out_dir
.join("src/peripherals")
.join(format!("{}_{}.rs", module, version)),
)
.unwrap();
let data = items.to_string().replace("] ", "]\n");
// Remove inner attributes like #![no_std]
let re = Regex::new("# *! *\\[.*\\]").unwrap();
let data = re.replace_all(&data, "");
file.write_all(data.as_bytes()).unwrap();
}
// Generate Cargo.toml
let mut contents = include_bytes!("../res/Cargo.toml").to_vec();
for name in &chip_core_names {
write!(&mut contents, "{} = []\n", name.to_ascii_lowercase()).unwrap();
}
fs::write(self.opts.out_dir.join("Cargo.toml"), contents).unwrap();
// copy misc files
fs::write(self.opts.out_dir.join("build.rs"), include_bytes!("../res/build.rs")).unwrap();
fs::write(
self.opts.out_dir.join("src/lib.rs"),
include_bytes!("../res/src/lib.rs"),
)
.unwrap();
fs::write(
self.opts.out_dir.join("src/common.rs"),
chiptool::generate::COMMON_MODULE,
)
.unwrap();
fs::write(
self.opts.out_dir.join("src/metadata.rs"),
include_bytes!("../res/src/metadata.rs"),
)
.unwrap();
}
}
fn stringify<T: Debug>(metadata: T) -> String {
let mut metadata = format!("{:?}", metadata);
if metadata.starts_with('[') {
metadata = format!("&{}", metadata);
}
metadata = metadata.replace(": [", ": &[");
metadata = metadata.replace("kind: Ram", "kind: MemoryRegionKind::Ram");
metadata = metadata.replace("kind: Flash", "kind: MemoryRegionKind::Flash");
metadata
}
fn gen_opts() -> generate::Options {
generate::Options {
common_module: CommonModule::External(TokenStream::from_str("crate::common").unwrap()),
}
}
fn gen_memory_x(out_dir: &PathBuf, chip: &Chip) {
let mut memory_x = String::new();
let flash = chip.memory.iter().find(|r| r.name == "BANK_1").unwrap();
let ram = chip.memory.iter().find(|r| r.name == "SRAM").unwrap();
write!(memory_x, "MEMORY\n{{\n").unwrap();
write!(
memory_x,
" FLASH : ORIGIN = 0x{:x}, LENGTH = {}\n",
flash.address, flash.size,
)
.unwrap();
write!(
memory_x,
" RAM : ORIGIN = 0x{:x}, LENGTH = {}\n",
ram.address, ram.size,
)
.unwrap();
write!(memory_x, "}}").unwrap();
fs::create_dir_all(out_dir.join("memory_x")).unwrap();
let mut file = File::create(out_dir.join("memory_x").join("memory.x")).unwrap();
file.write_all(memory_x.as_bytes()).unwrap();
}

View File

@ -0,0 +1,33 @@
use std::env::args;
use std::path::PathBuf;
use stm32_metapac_gen::*;
fn main() {
let out_dir = PathBuf::from("build/stm32-metapac");
let data_dir = PathBuf::from("build/data");
let args: Vec<String> = args().collect();
let mut chips = match &args[..] {
[_, chip] => {
vec![chip.clone()]
}
[_] => std::fs::read_dir(data_dir.join("chips"))
.unwrap()
.filter_map(|res| res.unwrap().file_name().to_str().map(|s| s.to_string()))
.filter(|s| s.ends_with(".json"))
.map(|s| s.strip_suffix(".json").unwrap().to_string())
.collect(),
_ => panic!("usage: stm32-metapac-gen [chip?]"),
};
chips.sort();
let opts = Options {
out_dir,
data_dir,
chips,
};
Gen::new(opts).gen();
}