From 6f313f98fc8162c8dc7bac330fde927901cb9ba8 Mon Sep 17 00:00:00 2001 From: Ian McIntyre Date: Sat, 5 Jul 2025 16:24:52 -0400 Subject: First commit --- .cargo/config.toml | 2 + .gitignore | 2 + .gitmodules | 15 ++++ Cargo.toml.chiptool | 12 +++ Cargo.toml.svd2rust | 13 +++ Makefile | 102 ++++++++++++++++++++++ README.md | 74 ++++++++++++++++ chiptool | 1 + form | 1 + imxrt-ral | 1 + svd2rust | 1 + svdtools | 1 + transform.yaml | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 470 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 Cargo.toml.chiptool create mode 100644 Cargo.toml.svd2rust create mode 100644 Makefile create mode 100644 README.md create mode 160000 chiptool create mode 160000 form create mode 160000 imxrt-ral create mode 160000 svd2rust create mode 160000 svdtools create mode 100644 transform.yaml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..c9b00e8 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +dep-info-basedir = "." diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4e9f777 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +imxrt-svd2rust/ +imxrt-chiptool/ diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..aa3e766 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,15 @@ +[submodule "imxrt-ral"] + path = imxrt-ral + url = git@github.com:imxrt-rs/imxrt-ral.git +[submodule "svd2rust"] + path = svd2rust + url = git@github.com:rust-embedded/svd2rust.git +[submodule "chiptool"] + path = chiptool + url = git@github.com:embassy-rs/chiptool.git +[submodule "form"] + path = form + url = git@github.com:djmcgill/form.git +[submodule "svdtools"] + path = svdtools + url = git@github.com:rust-embedded/svdtools.git diff --git a/Cargo.toml.chiptool b/Cargo.toml.chiptool new file mode 100644 index 0000000..4397cf5 --- /dev/null +++ b/Cargo.toml.chiptool @@ -0,0 +1,12 @@ +[package] +name = "imxrt-chiptool" +version = "0.1.0" +edition = "2024" + +[dependencies] +cortex-m = { version = "0.7" } +cortex-m-rt = { version = "0.7", optional = true } +defmt = { version = "1", optional = true } + +[features] +rt = ["cortex-m-rt/device"] diff --git a/Cargo.toml.svd2rust b/Cargo.toml.svd2rust new file mode 100644 index 0000000..1d707c8 --- /dev/null +++ b/Cargo.toml.svd2rust @@ -0,0 +1,13 @@ +[package] +name = "imxrt-svd2rust" +version = "0.1.0" +edition = "2021" + +[dependencies] +critical-section = { version = "1.0", optional = true } +cortex-m = "0.7" +cortex-m-rt = { version = "0.7", optional = true } +vcell = "0.1.2" + +[features] +rt = ["cortex-m-rt/device"] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1811907 --- /dev/null +++ b/Makefile @@ -0,0 +1,102 @@ +CODEGEN_TOOL_PROFILE := release +PAC_PROFILE := release +TIMINGS ?= --timings + +-include chiptool/target/$(CODEGEN_TOOL_PROFILE)/chiptool.d +-include svd2rust/target/$(CODEGEN_TOOL_PROFILE)/svd2rust.d +-include form/target/$(CODEGEN_TOOL_PROFILE)/form.d +-include svdtools/target/$(CODEGEN_TOOL_PROFILE)/svdtools.d + +CHIPTOOL = chiptool/target/$(CODEGEN_TOOL_PROFILE)/chiptool +SVD2RUST = svd2rust/target/$(CODEGEN_TOOL_PROFILE)/svd2rust +FORM = form/target/$(CODEGEN_TOOL_PROFILE)/form +SVDTOOLS = svdtools/target/$(CODEGEN_TOOL_PROFILE)/svdtools + +$(CHIPTOOL): + cargo build --manifest-path=chiptool/Cargo.toml --profile=$(CODEGEN_TOOL_PROFILE) + +$(SVD2RUST): + cargo build --manifest-path=svd2rust/Cargo.toml --profile=$(CODEGEN_TOOL_PROFILE) + +$(FORM): + cargo build --manifest-path=form/Cargo.toml --profile $(CODEGEN_TOOL_PROFILE) + +$(SVDTOOLS): + cargo build --manifest-path=svdtools/Cargo.toml --profile $(CODEGEN_TOOL_PROFILE) + +.PHONY: codegen_tools +codegen_tools: $(CHIPTOOL) $(RALTOOL) $(SVD2RUST) $(FORM) $(SVDTOOLS) + +.PHONY: test_codegen_tools +test_codegen_tools: codegen_tools + $(CHIPTOOL) --help + $(SVD2RUST) --help + $(FORM) --help + $(SVDTOOLS) --help + +.PHONY: imxrt-ral.shootout +imxrt-ral.shootout: + @cargo update --manifest-path=imxrt-ral/Cargo.toml + + @cargo clean --manifest-path=imxrt-ral/Cargo.toml --profile=$(PAC_PROFILE) + cargo build --manifest-path=imxrt-ral/Cargo.toml --profile=$(PAC_PROFILE) --target=thumbv7em-none-eabihf --package=imxrt-ral --features=imxrt1011,rt $(TIMINGS) + + @cargo clean --manifest-path=imxrt-ral/Cargo.toml --profile=$(PAC_PROFILE) + cargo build --manifest-path=imxrt-ral/Cargo.toml --profile=$(PAC_PROFILE) --target=thumbv7em-none-eabihf --package=imxrt-ral --features=imxrt1062,rt $(TIMINGS) + + @cargo clean --manifest-path=imxrt-ral/Cargo.toml --profile=$(PAC_PROFILE) + cargo build --manifest-path=imxrt-ral/Cargo.toml --profile=$(PAC_PROFILE) --target=thumbv7em-none-eabihf --package=imxrt-ral --features=imxrt1176_cm7,rt $(TIMINGS) + + @cargo clean --manifest-path=imxrt-ral/Cargo.toml --profile=$(PAC_PROFILE) + cargo build --manifest-path=imxrt-ral/Cargo.toml --profile=$(PAC_PROFILE) --target=thumbv8m.main-none-eabihf --package=imxrt-ral --features=imxrt1189_cm33,rt $(TIMINGS) + +imxrt-svd2rust: + @mkdir -p $@ + +imxrt-ral/svd/%.svd.patched: $(SVDTOOLS) + SVDTOOLS=../$(SVDTOOLS) $(MAKE) -C imxrt-ral svd/$*.svd.patched + +imxrt-svd2rust/%: imxrt-ral/svd/%.svd.patched imxrt-svd2rust $(SVD2RUST) $(FORM) + @mkdir -p $@ + @cp Cargo.toml.svd2rust $@/Cargo.toml + @$(SVD2RUST) -i $< --output-dir $@ + @$(FORM) --input $@/lib.rs --outdir $@/src/ + @rm -f @/lib.rs + @cargo fmt --manifest-path=$@/Cargo.toml + +.PHONY: imxrt-svd2rust.shootout +imxrt-svd2rust.shootout: imxrt-svd2rust/imxrt1011 imxrt-svd2rust/imxrt1062 + @cargo update --manifest-path=imxrt-svd2rust/imxrt1011/Cargo.toml + @cargo clean --manifest-path=imxrt-svd2rust/imxrt1011/Cargo.toml + cargo build --manifest-path=imxrt-svd2rust/imxrt1011/Cargo.toml --profile=$(PAC_PROFILE) --target=thumbv7em-none-eabihf --features=rt $(TIMINGS) + + @cargo update --manifest-path=imxrt-svd2rust/imxrt1062/Cargo.toml + @cargo clean --manifest-path=imxrt-svd2rust/imxrt1062/Cargo.toml + cargo build --manifest-path=imxrt-svd2rust/imxrt1062/Cargo.toml --profile=$(PAC_PROFILE) --target=thumbv7em-none-eabihf --features=rt $(TIMINGS) + +imxrt-chiptool: + @mkdir -p $@ + +imxrt-chiptool/%: imxrt-ral/svd/%.svd.patched imxrt-chiptool $(CHIPTOOL) $(FORM) + @mkdir -p $@ + @cp Cargo.toml.chiptool $@/Cargo.toml + @cd $@ && ../../$(CHIPTOOL) generate --svd ../../$< --transform ../../transform.yaml && ../../$(FORM) --input lib.rs --outdir src/ && rm lib.rs + @cargo fmt --manifest-path=$@/Cargo.toml + +.PHONY: imxrt-chiptool.shootout +imxrt-chiptool.shootout: imxrt-chiptool/imxrt1011 imxrt-chiptool/imxrt1062 imxrt-chiptool/imxrt1176_cm7 imxrt-chiptool/imxrt1189_cm33 + @cargo update --manifest-path=imxrt-chiptool/imxrt1011/Cargo.toml + @cargo clean --manifest-path=imxrt-chiptool/imxrt1011/Cargo.toml + cargo build --manifest-path=imxrt-chiptool/imxrt1011/Cargo.toml --profile=$(PAC_PROFILE) --target=thumbv7em-none-eabihf --features=rt $(TIMINGS) + + @cargo update --manifest-path=imxrt-chiptool/imxrt1062/Cargo.toml + @cargo clean --manifest-path=imxrt-chiptool/imxrt1062/Cargo.toml + cargo build --manifest-path=imxrt-chiptool/imxrt1062/Cargo.toml --profile=$(PAC_PROFILE) --target=thumbv7em-none-eabihf --features=rt $(TIMINGS) + + @cargo update --manifest-path=imxrt-chiptool/imxrt1176_cm7/Cargo.toml + @cargo clean --manifest-path=imxrt-chiptool/imxrt1176_cm7/Cargo.toml + cargo build --manifest-path=imxrt-chiptool/imxrt1176_cm7/Cargo.toml --profile=$(PAC_PROFILE) --target=thumbv7em-none-eabihf --features=rt $(TIMINGS) + + @cargo update --manifest-path=imxrt-chiptool/imxrt1189_cm33/Cargo.toml + @cargo clean --manifest-path=imxrt-chiptool/imxrt1189_cm33/Cargo.toml + cargo build --manifest-path=imxrt-chiptool/imxrt1189_cm33/Cargo.toml --profile=$(PAC_PROFILE) --target=thumbv8m.main-none-eabihf --features=rt $(TIMINGS) diff --git a/README.md b/README.md new file mode 100644 index 0000000..3fceeed --- /dev/null +++ b/README.md @@ -0,0 +1,74 @@ +How long does it take to build a peripheral access crate (PAC) for different i.MX RT MCUs? +Let's find out! +[Here](https://www.mciantyre.dev/2025/06/30/imxrt-pac-shootout.html) are my measurements. + +We'll use three different PAC representations: + +1. the classic [svd2rust] PAC. +2. the [chiptool] PAC, preferred by [embassy]. +3. the register access layer (RAL) design, first pioneered by [stm32ral] and + later adopted by [imxrt-ral]. + +[svd2rust]: https://github.com/rust-embedded/svd2rust +[stm32ral]: https://github.com/adamgreig/stm32ral +[imxrt-ral]: https://github.com/imxrt-rs/imxrt-ral +[embassy]: https://github.com/embassy-rs +[chiptool]: https://github.com/embassy-rs/chiptool + +With each of these, we'll build PACs for four different i.MX RT MCUs: + +1. iMXRT1011 +2. iMXRT1062 +3. iMXRT1176 (Cortex-M7 only) +4. iMXRT1189 (Cortex-M33 only) + +We'll clean-build all PACs in release mode, targeting the best architecture profile for each MCU. +Note that this also includes the time to build PAC dependencies. +We'll trust Cargo's reporting of how long it takes. + +## Try it out + +Clone this repository along with all of its submodules. + +``` +git clone --recurse-submodules https://git.mciantyre.dev/imxrt-pac-shootout +``` + +Install the Rust targets we're using to build PACs: + +``` +rustup target add thumbv7em-none-eabihf thumbv8m.main-none-eabihf +``` + +The rest of these commands should automatically build the tools and intermediates +needed for codegen. + +### imxrt-ral + +This one is the simplest: clean-build the package for each MCU. + +``` +make -j imxrt-ral.shootout +``` + +### imxrt-svd2rust + +Generate four PACs using `svd2rust`, supplying the same patched SVDs used by imxrt-ral. +Separate each PAC's modules with `form`, and format them with `rustfmt`. +Then, build all four PACs. + +``` +make -j imxrt-svd2rust.shootout +``` + +### imxrt-chiptool + +Generate four PACs using `chiptool`, supplying the same patched SVDs used by imxrt-ral. +Use a transform file that's equivalent to what imxrt-ral uses. + +Separate each PAC's modules with `form`, and format them with `rustfmt`. +Then, build all four PACs. + +``` +make -j imxrt-chiptool.shootout +``` diff --git a/chiptool b/chiptool new file mode 160000 index 0000000..6651cd0 --- /dev/null +++ b/chiptool @@ -0,0 +1 @@ +Subproject commit 6651cd0877390fdd3c76af037244e795bb867daa diff --git a/form b/form new file mode 160000 index 0000000..42afa0b --- /dev/null +++ b/form @@ -0,0 +1 @@ +Subproject commit 42afa0b7b8fd70458401c6bfb66979c9d78a8f92 diff --git a/imxrt-ral b/imxrt-ral new file mode 160000 index 0000000..9b21c91 --- /dev/null +++ b/imxrt-ral @@ -0,0 +1 @@ +Subproject commit 9b21c91b8bc9c937e8d2ea52b0e46359928122f3 diff --git a/svd2rust b/svd2rust new file mode 160000 index 0000000..23464b3 --- /dev/null +++ b/svd2rust @@ -0,0 +1 @@ +Subproject commit 23464b37d2bd90e7dc19be853b4337c0e5797c4a diff --git a/svdtools b/svdtools new file mode 160000 index 0000000..ce6ff66 --- /dev/null +++ b/svdtools @@ -0,0 +1 @@ +Subproject commit ce6ff6663b752d6ed8732432c36008b4386eb7d0 diff --git a/transform.yaml b/transform.yaml new file mode 100644 index 0000000..c599601 --- /dev/null +++ b/transform.yaml @@ -0,0 +1,245 @@ +# A port of the raltool-cfg.yaml from imxrt-ral. This is how raltool +# transforms its peripherals, so it's only fair that chiptool does +# the same. + +transforms: + # Transform device names, keeping the RAL convention. + - !Rename + from: Mimxrt1011 + to: imxrt1011 + type: Device + - !Rename + from: Mimxrt1015 + to: imxrt1015 + type: Device + - !Rename + from: Mimxrt1021 + to: imxrt1021 + type: Device + - !Rename + from: Mimxrt1051 + to: imxrt1051 + type: Device + - !Rename + from: Mimxrt1052 + to: imxrt1052 + type: Device + - !Rename + from: Mimxrt1061 + to: imxrt1061 + type: Device + - !Rename + from: Mimxrt1062 + to: imxrt1062 + type: Device + - !Rename + from: Mimxrt1064 + to: imxrt1064 + type: Device + - !Rename + from: Mimxrt1176Cm7 + to: imxrt1176_cm7 + type: Device + - !Rename + from: Mimxrt1176Cm4 + to: imxrt1176_cm4 + type: Device + - !Rename + from: Mimxrt1189Cm33 + to: imxrt1189_cm33 + type: Device + - !Rename + from: Mimxrt1189Cm7 + to: imxrt1189_cm7 + type: Device + - !Rename + from: pit::Pit1 + to: pit::Pit + type: Block + - !Rename + from: usb::Usb1 + to: usb::Usb + type: Block + - !DeleteEnums + from: usb::vals::Fs2 + # Combine GPT OCR and ICR registrers for 10xx MCUs. + # This allows it to match the 11xx MCUs, and reduce + # code bloat. + - !MakeRegisterArray + blocks: gpt::Gpt(\d) + from: OCR(\d) + to: OCR + - !MakeRegisterArray + blocks: gpt::Gpt(\d) + from: ICR(\d) + to: ICR + # Drop select enums from GPT fields. These extra enums + # are present in 11xx SVDs and prevent the tool from + # combining with the 10xx GPT definition. + - !DeleteEnums + from: gpt::vals::Im(\d) + - !DeleteEnums + from: gpt::vals::Om(\d) + - !DeleteEnums + from: gpt::vals::Fo(\d) + - !DeleteEnums + from: gpt::vals::Sr(\d) + - !DeleteEnums + from: gpt::vals::Of(\d) + - !DeleteEnums + from: gpt::vals::If(\d) + - !DeleteEnums + from: gpt::vals::Of(\d)ie + - !DeleteEnums + from: gpt::vals::If(\d)ie + # Move the CAN wrapper instance number to the far right + # so it's properly parsed. + - !Rename + from: CAN(\d)_WRAPPER + to: CAN_WRAPPER$1 + type: Block + # This resembles a XECC_FLEXSPI peripheral. + # It consolidates when there's a number at the end. + - !Rename + from: XECC_SEMC + to: XECC_SEMC0 + type: Block + # This peripheral is tricky to support. + # + # - It has clusters in clusters. While we can generate code for this, + # we can't easily add macro support for this. + # - It has clusters that alias each other. This is trickier to support + # in today's codegen tool, so we're punting. + - !Delete + from: caam::Caam + # 1176 CM7 has GPIO blocks under a "cm7_gpio" module. Change this + # so that they're under a "gpio" module. Also, rename the block so + # that it matches the 10xx GPIO block name, and can be combined. + - !Rename + from: cm7_gpio::Cm7Gpio2 + to: gpio::Gpio1 + type: Block + # Same goes for the 1176 CM4: rename for combining. + - !Rename + from: gpio::Gpio2 + to: gpio::Gpio1 + type: Block + # Change the fast GPIO numbers on the 1176 CM7 so that they have a + # unique instance number. Add 10 to make it distinct. This is faily hacky, + # so TODO make this better. + - !Rename + from: CM7_GPIO2 + to: FAST_GPIO20 + type: Block + - !Rename + from: CM7_GPIO3 + to: FAST_GPIO30 + type: Block + # Similar number suffixes result in duplicate instance types. Define unique + # numbers (that are a bit less hacky, maybe). + - !Rename + from: PGMC_CPC0_MIF0 + to: PGMC_CPC_MIF00 + type: Block + - !Rename + from: PGMC_CPC0_MIF1 + to: PGMC_CPC_MIF01 + type: Block + - !Rename + from: PGMC_CPC1_MIF0 + to: PGMC_CPC_MIF10 + type: Block + - !Rename + from: PGMC_CPC1_MIF1 + to: PGMC_CPC_MIF11 + type: Block + # 1176 LPSPI has fewer enums which prevent combining. Remove them from + # the 10xx variants. They're simple, intuitive bool fields, so it's no + # bit deal to remove. + - !DeleteEnums + from: lpspi::vals::Hren + - !DeleteEnums + from: lpspi::vals::Hrpol + - !DeleteEnums + from: lpspi::vals::Hrsel + - !DeleteEnums + from: lpspi::vals::Pcspol + # The 1189 has two DMA peripherals. Avoid collision when unifying with 10xx + # names. + - !Delete + from: dma3::Dma3 + # DMA and DMAMUX are suffixed with numbers on the 1176, since each core + # has its own instance. They're also suffixed on 10xx chips, even though + # there's just one instnace. Rename them so that the names are the same across + # all chips. + - !Rename + from: dma(\d)::Dma(\d) + to: dma::Dma + type: All + - !Rename + from: DMA(\d) + to: DMA + type: All + - !Rename + from: dmamux(\d)::Dmamux(\d) + to: dmamux::Dmamux + type: All + - !Rename + from: DMAMUX(\d) + to: DMAMUX + type: All + - !RenameRegisters + block: ocotp::Ocotp + from: HW_OCOTP_(.*) + to: $1 + # Field is needlessly named 'AM1F' on the 1176. + # All 1000-series use AM1IE. The field meaning + # is the same regardless, and this lets us combine + # the LPI2C blocks. + - !RenameFields + fieldset: lpi2c::regs::Sier + from: AM1F + to: AM1IE + - !RenameFields + fieldset: src::regs::Srsr + from: LOCKUP + to: LOCKUP_SYSRESETREQ + # Groups of 1189 peripherals that use derivedFrom but with meaningful names + # instead of plain numbering. raltool only handles the numbered case, so + # delete them until someone needs them. + - !Delete + from: aon_mif_ln28fdsoi_spllram::AonMifLn28fdsoiSpllram + - !Delete + from: aon_mif_s28spregh::AonMifS28spregh + - !Delete + from: aon_mix_slice::AonMixSlice + - !Delete + from: enetc0_revmii_mac::Enetc0RevmiiMac + - !Delete + from: enetc0_revmii_phy::Enetc0RevmiiPhy + - !Delete + from: ethernet_pll::EthernetPll + - !Delete + from: mu2_mua::Mu2Mua + - !Delete + from: sw0_global::Sw0Global + - !Delete + from: tstmr2_tstmra::Tstmr2Tstmra + - !Delete + from: xcache_pc::XcachePc + - !Delete + from: m33_pcf::M33Pcf1 + # Aliased cluster arrays are not supported by raltool at the time of writing. + - !Delete + from: ecat::RxErrorCntr + - !Delete + from: ecat::ForwardedRxErrorCntr + - !Delete + from: ecat::LostLinkCntr + - !Delete + from: ecat::Fmmu + - !Delete + from: ecat::Syncmanager + # This one probably just needs some renaming to work. + - !Delete + from: mu2_mub::Mu2Mub -- cgit v1.2.3