aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/build.yml417
-rw-r--r--CHANGELOG.md13
-rw-r--r--Cargo.toml13
-rw-r--r--book/en/src/SUMMARY.md8
-rw-r--r--book/en/src/by-example.md2
-rw-r--r--book/en/src/by-example/app.md35
-rw-r--r--book/en/src/by-example/new.md3
-rw-r--r--book/en/src/by-example/resources.md18
-rw-r--r--book/en/src/by-example/tasks.md13
-rw-r--r--book/en/src/by-example/tips.md16
-rw-r--r--book/en/src/by-example/types-send-sync.md2
-rw-r--r--book/en/src/heterogeneous.md6
-rw-r--r--book/en/src/homogeneous.md6
-rw-r--r--book/en/src/internals/access.md12
-rw-r--r--book/en/src/internals/ceilings.md4
-rw-r--r--book/en/src/internals/critical-sections.md24
-rw-r--r--book/en/src/internals/interrupt-configuration.md4
-rw-r--r--book/en/src/internals/late-resources.md8
-rw-r--r--book/en/src/internals/non-reentrancy.md8
-rw-r--r--book/en/src/internals/tasks.md24
-rw-r--r--book/en/src/internals/timer-queue.md28
-rw-r--r--book/en/src/migration.md235
-rw-r--r--book/en/src/migration/migration_rtic.md (renamed from book/en/src/migration_rtic.md)0
-rw-r--r--book/en/src/migration/migration_v4.md232
-rw-r--r--book/en/src/migration/migration_v5.md96
-rw-r--r--book/en/src/preface.md6
-rw-r--r--examples/baseline.rs8
-rw-r--r--examples/binds.rs12
-rw-r--r--examples/capacity.rs8
-rw-r--r--examples/cfg.rs13
-rw-r--r--examples/destructure.rs9
-rw-r--r--examples/double_schedule.rs39
-rw-r--r--examples/generics.rs9
-rw-r--r--examples/hardware.rs12
-rw-r--r--examples/idle.rs12
-rw-r--r--examples/init.rs12
-rw-r--r--examples/late.rs9
-rw-r--r--examples/lock.rs9
-rw-r--r--examples/message.rs8
-rw-r--r--examples/not-send.rs11
-rw-r--r--examples/not-sync.rs12
-rw-r--r--examples/only-shared-access.rs5
-rw-r--r--examples/periodic.rs9
-rw-r--r--examples/peripherals-taken.rs8
-rw-r--r--examples/pool.rs13
-rw-r--r--examples/preempt.rs8
-rw-r--r--examples/ramfunc.rs8
-rw-r--r--examples/resource-user-struct.rs63
-rw-r--r--examples/resource.rs13
-rw-r--r--examples/schedule.rs8
-rw-r--r--examples/shared-with-init.rs11
-rw-r--r--examples/smallest.rs2
-rw-r--r--examples/t-binds.rs8
-rw-r--r--examples/t-cfg-resources.rs14
-rw-r--r--examples/t-cfg.rs13
-rw-r--r--examples/t-htask-main.rs12
-rw-r--r--examples/t-idle-main.rs14
-rw-r--r--examples/t-init-main.rs8
-rw-r--r--examples/t-late-not-send.rs11
-rw-r--r--examples/t-resource.rs13
-rw-r--r--examples/t-schedule.rs12
-rw-r--r--examples/t-spawn.rs12
-rw-r--r--examples/t-stask-main.rs14
-rw-r--r--examples/task.rs8
-rw-r--r--examples/types.rs13
-rw-r--r--heterogeneous/Cargo.toml18
-rw-r--r--heterogeneous/README.md1
-rw-r--r--heterogeneous/examples/smallest.rs7
-rw-r--r--heterogeneous/examples/x-init-2.rs39
-rw-r--r--heterogeneous/examples/x-init.rs26
-rw-r--r--heterogeneous/examples/x-schedule.rs36
-rw-r--r--heterogeneous/examples/x-spawn.rs20
-rw-r--r--heterogeneous/src/lib.rs99
-rw-r--r--homogeneous/Cargo.toml17
-rw-r--r--homogeneous/README.md1
-rw-r--r--homogeneous/examples/smallest.rs7
-rw-r--r--homogeneous/examples/x-init-2.rs39
-rw-r--r--homogeneous/examples/x-init.rs26
-rw-r--r--homogeneous/examples/x-schedule.rs36
-rw-r--r--homogeneous/examples/x-spawn.rs20
-rw-r--r--homogeneous/src/lib.rs99
-rw-r--r--macros/Cargo.toml7
-rw-r--r--macros/src/analyze.rs41
-rw-r--r--macros/src/check.rs134
-rw-r--r--macros/src/codegen.rs167
-rw-r--r--macros/src/codegen/assertions.rs26
-rw-r--r--macros/src/codegen/dispatchers.rs290
-rw-r--r--macros/src/codegen/hardware_tasks.rs50
-rw-r--r--macros/src/codegen/idle.rs45
-rw-r--r--macros/src/codegen/init.rs102
-rw-r--r--macros/src/codegen/locals.rs9
-rw-r--r--macros/src/codegen/module.rs48
-rw-r--r--macros/src/codegen/post_init.rs149
-rw-r--r--macros/src/codegen/pre_init.rs109
-rw-r--r--macros/src/codegen/resources.rs67
-rw-r--r--macros/src/codegen/resources_struct.rs19
-rw-r--r--macros/src/codegen/schedule.rs23
-rw-r--r--macros/src/codegen/schedule_body.rs14
-rw-r--r--macros/src/codegen/software_tasks.rs181
-rw-r--r--macros/src/codegen/spawn.rs28
-rw-r--r--macros/src/codegen/spawn_body.rs24
-rw-r--r--macros/src/codegen/timer_queue.rs40
-rw-r--r--macros/src/codegen/util.rs148
-rw-r--r--macros/src/lib.rs9
-rw-r--r--macros/src/tests.rs1
-rw-r--r--macros/src/tests/multi.rs59
-rw-r--r--macros/src/tests/single.rs8
-rw-r--r--src/cyccnt.rs4
-rw-r--r--src/export.rs18
-rw-r--r--src/lib.rs11
-rw-r--r--src/tq.rs6
-rw-r--r--ui/single/exception-invalid.rs4
-rw-r--r--ui/single/exception-systick-used.rs4
-rw-r--r--ui/single/extern-interrupt-not-enough.rs4
-rw-r--r--ui/single/extern-interrupt-used.rs4
-rw-r--r--ui/single/locals-cfg.rs9
-rw-r--r--ui/single/locals-cfg.stderr30
-rw-r--r--ui/single/resources-cfg.rs10
-rw-r--r--ui/single/resources-cfg.stderr66
-rw-r--r--ui/single/task-priority-too-high.rs10
-rw-r--r--ui/single/task-priority-too-high.stderr16
121 files changed, 1853 insertions, 2348 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 3e5a90e5..8da98678 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -14,7 +14,7 @@ jobs:
# Run cargo fmt --check, includes macros/
style:
name: style
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v1
@@ -36,7 +36,7 @@ jobs:
# Compilation check
check:
name: check
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
strategy:
matrix:
target:
@@ -45,11 +45,32 @@ jobs:
- x86_64-unknown-linux-gnu
toolchain:
- stable
- - 1.36.0
steps:
- name: Checkout
uses: actions/checkout@v2
+ - name: Cache cargo dependencies
+ uses: actions/cache@v2
+ with:
+ path: |
+ - ~/.cargo/bin/
+ - ~/.cargo/registry/index/
+ - ~/.cargo/registry/cache/
+ - ~/.cargo/git/db/
+ key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ ${{ runner.OS }}-cargo-
+
+ - name: Cache build output dependencies
+ uses: actions/cache@v2
+ with:
+ path: target
+ key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ ${{ runner.OS }}-build-
+
- name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }})
uses: actions-rs/toolchain@v1
with:
@@ -57,10 +78,6 @@ jobs:
target: ${{ matrix.target }}
override: true
- - name: Disable optimisation profiles
- if: matrix.toolchain == '1.36.0'
- run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
-
- name: cargo check
uses: actions-rs/cargo@v1
with:
@@ -68,10 +85,10 @@ jobs:
command: check
args: --target=${{ matrix.target }}
- # Verify all examples
+ # Verify all examples, checks
checkexamples:
name: checkexamples
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
strategy:
matrix:
target:
@@ -83,41 +100,109 @@ jobs:
- name: Checkout
uses: actions/checkout@v2
+ - name: Cache cargo dependencies
+ uses: actions/cache@v2
+ with:
+ path: |
+ - ~/.cargo/bin/
+ - ~/.cargo/registry/index/
+ - ~/.cargo/registry/cache/
+ - ~/.cargo/git/db/
+ key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ ${{ runner.OS }}-cargo-
+
+ - name: Cache build output dependencies
+ uses: actions/cache@v2
+ with:
+ path: target
+ key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ ${{ runner.OS }}-build-
+
- name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }})
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.toolchain }}
target: ${{ matrix.target }}
override: true
- - uses: actions-rs/cargo@v1
- with:
- use-cross: false
- command: check
- args: --examples --target=${{ matrix.target }} --features __min_r1_43
+ components: llvm-tools-preview
- - name: cargo check -p homogeneous
+ - name: Check the examples
+ if: matrix.target == 'thumbv7m-none-eabi'
+ env:
+ V7: __v7
uses: actions-rs/cargo@v1
with:
use-cross: false
command: check
- args: -p homogeneous --examples --target=${{ matrix.target }}
+ args: --examples --target=${{ matrix.target }} --features __min_r1_43,${{ env.V7 }}
- - name: Install QEMU
- run: |
- mkdir qemu
- curl -L https://github.com/japaric/qemu-bin/raw/master/14.04/qemu-system-arm-2.12.0 > qemu/qemu-system-arm
- chmod +x qemu/qemu-system-arm
+ # Verify the example output with run-pass tests
+ testexamples:
+ name: testexamples
+ runs-on: ubuntu-20.04
+ strategy:
+ matrix:
+ target:
+ - thumbv7m-none-eabi
+ - thumbv6m-none-eabi
+ toolchain:
+ - stable
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+
+ - name: Cache cargo dependencies
+ uses: actions/cache@v2
+ with:
+ path: |
+ - ~/.cargo/bin/
+ - ~/.cargo/registry/index/
+ - ~/.cargo/registry/cache/
+ - ~/.cargo/git/db/
+ key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ ${{ runner.OS }}-cargo-
+
+ - name: Cache build output dependencies
+ uses: actions/cache@v2
+ with:
+ path: target
+ key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ ${{ runner.OS }}-build-
+
+ - name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }})
+ uses: actions-rs/toolchain@v1
+ with:
+ toolchain: ${{ matrix.toolchain }}
+ target: ${{ matrix.target }}
+ override: true
+ components: llvm-tools-preview
- - name: Setup arm-none-eabi-gcc
- uses: fiam/arm-none-eabi-gcc@v1
+ # Use precompiled binutils
+ - name: cargo install cargo-binutils
+ uses: actions-rs/install@v0.1
with:
- release: '9-2019-q4' # The arm-none-eabi-gcc release to use.
+ crate: cargo-binutils
+ version: latest
+ use-tool-cache: true
+
+ - name: Install QEMU
+ run: |
+ sudo apt update
+ sudo apt install -y qemu-system-arm
- name: Run-pass tests
run: |
- # Add QEMU to the path
+ # Print the path
echo $PATH
- PATH=$(pwd)/qemu:$PATH
+
arm_example() {
local COMMAND=$1
local EXAMPLE=$2
@@ -145,7 +230,7 @@ jobs:
else
cargo $COMMAND $CARGO_FLAGS
fi
- arm-none-eabi-objcopy -O ihex target/${{ matrix.target }}/$BUILD_MODE/examples/$EXAMPLE ci/builds/${EXAMPLE}_${FEATURES_STR}${BUILD_MODE}_${BUILD_NUM}.hex
+ cargo objcopy $CARGO_FLAGS -- -O ihex ci/builds/${EXAMPLE}_${FEATURES_STR}${BUILD_MODE}_${BUILD_NUM}.hex
}
mkdir -p ci/builds
@@ -190,15 +275,13 @@ jobs:
$td/pool.run
grep 'foo(0x2' $td/pool.run
grep 'bar(0x2' $td/pool.run
- arm-none-eabi-objcopy -O ihex target/${{ matrix.target }}/debug/examples/$ex \
- ci/builds/${ex}___v7_debug_1.hex
+ cargo objcopy --example $ex --target ${{ matrix.target }} --features __v7 -- -O ihex ci/builds/${ex}___v7_debug_1.hex
cargo run --example $ex --target ${{ matrix.target }} --features __v7 --release >\
$td/pool.run
grep 'foo(0x2' $td/pool.run
grep 'bar(0x2' $td/pool.run
- arm-none-eabi-objcopy -O ihex target/${{ matrix.target }}/release/examples/$ex \
- ci/builds/${ex}___v7_release_1.hex
+ cargo objcopy --example $ex --target ${{ matrix.target }} --features __v7 --release -- -O ihex ci/builds/${ex}___v7_release_1.hex
rm -rf $td
@@ -256,17 +339,39 @@ jobs:
# Check the correctness of macros/ crate
checkmacros:
name: checkmacros
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
strategy:
matrix:
target:
- x86_64-unknown-linux-gnu
toolchain:
- stable
- - 1.36.0
steps:
- name: Checkout
uses: actions/checkout@v2
+
+ - name: Cache cargo dependencies
+ uses: actions/cache@v2
+ with:
+ path: |
+ - ~/.cargo/bin/
+ - ~/.cargo/registry/index/
+ - ~/.cargo/registry/cache/
+ - ~/.cargo/git/db/
+ key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ ${{ runner.OS }}-cargo-
+
+ - name: Cache build output dependencies
+ uses: actions/cache@v2
+ with:
+ path: target
+ key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ ${{ runner.OS }}-build-
+
- name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }})
uses: actions-rs/toolchain@v1
with:
@@ -274,10 +379,6 @@ jobs:
target: ${{ matrix.target }}
override: true
- - name: Disable optimisation profiles
- if: matrix.toolchain == '1.36.0'
- run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
-
- name: cargo check
uses: actions-rs/cargo@v1
with:
@@ -285,112 +386,175 @@ jobs:
command: check
args: --manifest-path macros/Cargo.toml --target=${{ matrix.target }}
- # Run test suite for thumbv7m
- testv7:
- name: testv7
- runs-on: ubuntu-latest
+ # Run the macros test-suite
+ testmacros:
+ name: testmacros
+ runs-on: ubuntu-20.04
+ strategy:
+ matrix:
+ target:
+ - x86_64-unknown-linux-gnu
+ toolchain:
+ - stable
steps:
- name: Checkout
uses: actions/checkout@v2
- - name: Install Rust
+
+ - name: Cache cargo dependencies
+ uses: actions/cache@v2
+ with:
+ path: |
+ - ~/.cargo/bin/
+ - ~/.cargo/registry/index/
+ - ~/.cargo/registry/cache/
+ - ~/.cargo/git/db/
+ key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ ${{ runner.OS }}-cargo-
+
+ - name: Cache build output dependencies
+ uses: actions/cache@v2
+ with:
+ path: target
+ key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ ${{ runner.OS }}-build-
+
+ - name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }})
uses: actions-rs/toolchain@v1
with:
- toolchain: 1.36.0
- target: thumbv7m-none-eabi
+ toolchain: ${{ matrix.toolchain }}
+ target: ${{ matrix.target }}
override: true
- - name: Disable optimisation profiles
- run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
-
- - uses: actions-rs/cargo@v1
+ - name: cargo check
+ uses: actions-rs/cargo@v1
with:
use-cross: false
command: test
- args: --test single --features __v7
+ args: --manifest-path macros/Cargo.toml --target=${{ matrix.target }}
- # Run test suite for thumbv6m
- testv6:
- name: testv6
- runs-on: ubuntu-latest
+ # Run test suite for thumbv7m
+ testv7:
+ name: testv7
+ runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2
+
+ - name: Cache cargo dependencies
+ uses: actions/cache@v2
+ with:
+ path: |
+ - ~/.cargo/bin/
+ - ~/.cargo/registry/index/
+ - ~/.cargo/registry/cache/
+ - ~/.cargo/git/db/
+ key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-cargo-
+
+ - name: Cache build output dependencies
+ uses: actions/cache@v2
+ with:
+ path: target
+ key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-build-
+
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
- toolchain: 1.36.0
- target: thumbv6m-none-eabi
+ toolchain: stable
+ target: thumbv7m-none-eabi
override: true
- - name: Disable optimisation profiles
- run: sed -i '/^\[profile.*build-override]$/,/^$/{/^#/!{/^$/!d}}' Cargo.toml
-
- uses: actions-rs/cargo@v1
with:
use-cross: false
command: test
- args: --test single
+ args: --test single --features __v7
- # Verify all multicore examples
- checkmulticore:
- name: checkmulticore
- runs-on: ubuntu-latest
- strategy:
- matrix:
- target:
- - x86_64-unknown-linux-gnu
- toolchain:
- - nightly
+ # Run test suite for thumbv6m
+ testv6:
+ name: testv6
+ runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2
- - name: Install Rust ${{ matrix.toolchain }} with x86_64-unknown-linux-gnu
- uses: actions-rs/toolchain@v1
+ - name: Cache cargo dependencies
+ uses: actions/cache@v2
with:
- toolchain: ${{ matrix.toolchain }}
- target: x86_64-unknown-linux-gnu
- override: true
- - name: Install Rust ${{ matrix.toolchain }} with thumbv7m-none-eabi
- uses: actions-rs/toolchain@v1
+ path: |
+ - ~/.cargo/bin/
+ - ~/.cargo/registry/index/
+ - ~/.cargo/registry/cache/
+ - ~/.cargo/git/db/
+ key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-cargo-
+
+ - name: Cache build output dependencies
+ uses: actions/cache@v2
with:
- toolchain: ${{ matrix.toolchain }}
- target: thumbv7m-none-eabi
- override: true
- - name: Install Rust ${{ matrix.toolchain }} with thumbv6m-none-eabi
+ path: target
+ key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-build-
+
+ - name: Install Rust
uses: actions-rs/toolchain@v1
with:
- toolchain: ${{ matrix.toolchain }}
+ toolchain: stable
target: thumbv6m-none-eabi
override: true
+
- uses: actions-rs/cargo@v1
with:
- command: install
- args: microamp-tools --version 0.1.0-alpha.3
-
- - name: Check multi-core examples
- run: |
- cd heterogeneous
- exs=(
- smallest
- x-init-2
- x-init
- x-schedule
- x-spawn
- )
- for ex in ${exs[@]}; do
- cargo-microamp --example=$ex --target thumbv7m-none-eabi,thumbv6m-none-eabi --check
- done
+ use-cross: false
+ command: test
+ args: --test single
# Build documentation, check links
docs:
name: docs
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2
+ - name: Cache cargo dependencies
+ uses: actions/cache@v2
+ with:
+ path: |
+ - ~/.cargo/bin/
+ - ~/.cargo/registry/index/
+ - ~/.cargo/registry/cache/
+ - ~/.cargo/git/db/
+ key: ${{ runner.OS }}-cargo-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-cargo-
+
+ - name: Cache build output dependencies
+ uses: actions/cache@v2
+ with:
+ path: target
+ key: ${{ runner.OS }}-build-${{ hashFiles('**/Cargo.lock') }}
+ restore-keys: |
+ ${{ runner.OS }}-build-
+
+ - name: Cache pip installed linkchecker
+ uses: actions/cache@v2
+ with:
+ path: ~/.cache/pip
+ key: ${{ runner.os }}-pip
+ restore-keys: |
+ ${{ runner.os }}-pip-
+
- name: Set up Python 3.x
uses: actions/setup-python@v2
with:
@@ -422,7 +586,7 @@ jobs:
# Build the books
mdbook:
name: mdbook
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
steps:
- name: Checkout
uses: actions/checkout@v2
@@ -444,7 +608,7 @@ jobs:
- name: mdBook Action
uses: peaceiris/actions-mdbook@v1.1.11
with:
- mdbook-version: '0.3.1'
+ mdbook-version: 'latest'
- name: Build book in English
run: cd book/en && mdbook build
@@ -467,15 +631,16 @@ jobs:
# Only runs when pushing to master branch
deploy:
name: deploy
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
needs:
- style
- check
- checkexamples
+ - testexamples
- checkmacros
+ - testmacros
- testv7
- testv6
- - checkmulticore
- docs
- mdbook
# Only run this when pushing to master branch
@@ -498,8 +663,7 @@ jobs:
- name: mdBook Action
uses: peaceiris/actions-mdbook@v1.1.11
with:
- mdbook-version: '0.3.1'
- # mdbook-version: 'latest'
+ mdbook-version: 'latest'
- name: Remove cargo-config
run: rm -f .cargo/config
@@ -510,27 +674,37 @@ jobs:
- name: Build books
run: |
langs=( en ru )
- latest=0.5
- vers=( 0.4.x )
+ devver=( dev )
+ # The latest stable must be the first element in the array
+ vers=( 0.5.x 0.4.x )
+
+ # All releases start with "v"
+ # followed by MAJOR.MINOR.PATCH, see semver.org
+ # Retain MAJOR.MINOR as $stable
+ stable=${vers%.*}
+
+ echo "Stable version: $stable"
# Create directories
td=$(mktemp -d)
- mkdir -p $td/$latest/book/
- cp -r target/doc $td/$latest/api
+ mkdir -p $td/$devver/book/
+ cp -r target/doc $td/$devver/api
+
+ # Redirect the main site to the stable release
+ sed "s|URL|$stable|g" redirect.html > $td/index.html
- # sed fixes
- sed 's|URL|rtic/index.html|g' redirect.html > $td/$latest/api/index.html
- sed 's|URL|0.5|g' redirect.html > $td/index.html
- sed 's|URL|book/en|g' redirect.html > $td/$latest/index.html
+ # Create the redirects for dev-version
+ sed 's|URL|rtic/index.html|g' redirect.html > $td/$devver/api/index.html
+ sed 's|URL|book/en|g' redirect.html > $td/$devver/index.html
# Build books
for lang in ${langs[@]}; do
( cd book/$lang && mdbook build )
- cp -r book/$lang/book $td/$latest/book/$lang
- cp LICENSE-* $td/$latest/book/$lang/
+ cp -r book/$lang/book $td/$devver/book/$lang
+ cp LICENSE-* $td/$devver/book/$lang/
done
- # Build older versions
+ # Build older versions, including stable
root=$(pwd)
for ver in ${vers[@]}; do
prefix=${ver%.*}
@@ -555,6 +729,9 @@ jobs:
rm -rf $src
done
+ # Copy the stable book to the stable alias
+ cp -r $td/$stable $td/stable
+
# Forward CNAME file
cp CNAME $td/
mv $td/ bookstodeploy
@@ -576,13 +753,14 @@ jobs:
- style
- check
- checkexamples
+ - testexamples
- checkmacros
+ - testmacros
- testv7
- testv6
- - checkmulticore
- docs
- mdbook
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
steps:
- name: Mark the job as a success
run: exit 0
@@ -593,13 +771,14 @@ jobs:
- style
- check
- checkexamples
+ - testexamples
- checkmacros
+ - testmacros
- testv7
- testv6
- - checkmulticore
- docs
- mdbook
- runs-on: ubuntu-latest
+ runs-on: ubuntu-20.04
steps:
- name: Mark the job as a failure
run: exit 1
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3f33cd83..faecd10d 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,15 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
+## [v0.5.5] - 2020-08-27
+
+- Includes the previous soundness fix.
+- Fixes wrong use of the `cortex_m` crate which can cause some projects to stop compiling.
+
+## [v0.5.4] - 2020-08-26 - YANKED
+
+- **Soundness fix in RTIC**, it was previously possible to get the `cortex_m::Peripherals` more than once, causing UB.
+
## [v0.5.3] - 2020-06-12
- Added migration guide from `cortex-m-rtfm` to `cortex-m-rtic`
@@ -319,7 +328,9 @@ Yanked due to a soundness issue in `init`; the issue has been mostly fixed in v0
- Initial release
-[Unreleased]: https://github.com/rtic-rs/cortex-m-rtic/compare/v0.5.3...HEAD
+[Unreleased]: https://github.com/rtic-rs/cortex-m-rtic/compare/v0.5.5...HEAD
+[v0.5.5]: https://github.com/rtic-rs/cortex-m-rtic/compare/v0.5.4...v0.5.5
+[v0.5.4]: https://github.com/rtic-rs/cortex-m-rtic/compare/v0.5.3...v0.5.4
[v0.5.3]: https://github.com/rtic-rs/cortex-m-rtic/compare/v0.5.2...v0.5.3
[v0.5.2]: https://github.com/rtic-rs/cortex-m-rtic/compare/v0.5.1...v0.5.2
[v0.5.1]: https://github.com/rtic-rs/cortex-m-rtic/compare/v0.5.0...v0.5.1
diff --git a/Cargo.toml b/Cargo.toml
index 04670b98..6fe5fce3 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@ license = "MIT OR Apache-2.0"
name = "cortex-m-rtic"
readme = "README.md"
repository = "https://github.com/rtic-rs/cortex-m-rtic"
-version = "0.5.3"
+version = "0.5.5"
[lib]
name = "rtic"
@@ -50,12 +50,17 @@ required-features = ["__v7"]
name = "types"
required-features = ["__v7"]
+[[example]]
+name = "double_schedule"
+required-features = ["__v7"]
+
[dependencies]
cortex-m = "0.6.2"
-cortex-m-rtic-macros = { path = "macros", version = "0.5.0" }
+cortex-m-rtic-macros = { path = "macros", version = "0.5.2" }
rtic-core = "0.3.0"
cortex-m-rt = "0.6.9"
heapless = "0.5.0"
+bare-metal = "1.0.0"
[build-dependencies]
version_check = "0.9"
@@ -77,8 +82,6 @@ version = "0.5.2"
trybuild = "1"
[features]
-heterogeneous = ["cortex-m-rtic-macros/heterogeneous", "microamp"]
-homogeneous = ["cortex-m-rtic-macros/homogeneous"]
# used for testing this crate; do not use in applications
__v7 =[]
__min_r1_43 =[]
@@ -89,8 +92,6 @@ lto = true
[workspace]
members = [
- "heterogeneous",
- "homogeneous",
"macros",
]
diff --git a/book/en/src/SUMMARY.md b/book/en/src/SUMMARY.md
index 25aef811..e1a4a330 100644
--- a/book/en/src/SUMMARY.md
+++ b/book/en/src/SUMMARY.md
@@ -10,8 +10,10 @@
- [Types, Send and Sync](./by-example/types-send-sync.md)
- [Starting a new project](./by-example/new.md)
- [Tips & tricks](./by-example/tips.md)
-- [Migrating from v0.4.x to v0.5.0](./migration.md)
-- [Migrating from RTFM to RTIC](./migration_rtic.md)
+- [Migration Guides](./migration.md)
+ - [v0.5.x to v0.6.x](./migration/migration_v5.md)
+ - [v0.4.x to v0.5.x](./migration/migration_v4.md)
+ - [RTFM to RTIC](./migration/migration_rtic.md)
- [Under the hood](./internals.md)
- [Interrupt configuration](./internals/interrupt-configuration.md)
- [Non-reentrancy](./internals/non-reentrancy.md)
@@ -21,5 +23,3 @@
- [Ceiling analysis](./internals/ceilings.md)
- [Software tasks](./internals/tasks.md)
- [Timer queue](./internals/timer-queue.md)
-- [Homogeneous multi-core support](./homogeneous.md)
-- [Heterogeneous multi-core support](./heterogeneous.md)
diff --git a/book/en/src/by-example.md b/book/en/src/by-example.md
index d4527223..38985da1 100644
--- a/book/en/src/by-example.md
+++ b/book/en/src/by-example.md
@@ -9,7 +9,7 @@ is required to follow along.
[repository]: https://github.com/rtic-rs/cortex-m-rtic
-To run the examples on your laptop / PC you'll need the `qemu-system-arm`
+To run the examples on your computer you'll need the `qemu-system-arm`
program. Check [the embedded Rust book] for instructions on how to set up an
embedded development environment that includes QEMU.
diff --git a/book/en/src/by-example/app.md b/book/en/src/by-example/app.md
index e0f4f941..ab6f4524 100644
--- a/book/en/src/by-example/app.md
+++ b/book/en/src/by-example/app.md
@@ -7,7 +7,7 @@ This is the smallest possible RTIC application:
```
All RTIC applications use the [`app`] attribute (`#[app(..)]`). This attribute
-must be applied to a `const` item that contains items. The `app` attribute has
+must be applied to a `mod`-item. The `app` attribute has
a mandatory `device` argument that takes a *path* as a value. This path must
point to a *peripheral access crate* (PAC) generated using [`svd2rust`]
**v0.14.x** or newer. The `app` attribute will expand into a suitable entry
@@ -17,31 +17,25 @@ point so it's not required to use the [`cortex_m_rt::entry`] attribute.
[`svd2rust`]: https://crates.io/crates/svd2rust
[`cortex_m_rt::entry`]: ../../../api/cortex_m_rt_macros/attr.entry.html
-> **ASIDE**: Some of you may be wondering why we are using a `const` item as a
-> module and not a proper `mod` item. The reason is that using attributes on
-> modules requires a feature gate, which requires a nightly toolchain. To make
-> RTIC work on stable we use the `const` item instead. When more parts of macros
-> 1.2 are stabilized we'll move from a `const` item to a `mod` item and
-> eventually to a crate level attribute (`#![app]`).
-
## `init`
-Within the pseudo-module the `app` attribute expects to find an initialization
+Within the `app` module the attribute expects to find an initialization
function marked with the `init` attribute. This function must have signature
`fn(init::Context) [-> init::LateResources]` (the return type is not always
required).
This initialization function will be the first part of the application to run.
The `init` function will run *with interrupts disabled* and has exclusive access
-to Cortex-M and, optionally, device specific peripherals through the `core` and
-`device` fields of `init::Context`.
+to Cortex-M where the `bare_metal::CriticalSection` token is available as `cs`.
+And optionally, device specific peripherals through the `core` and `device` fields
+of `init::Context`.
`static mut` variables declared at the beginning of `init` will be transformed
into `&'static mut` references that are safe to access.
[`rtic::Peripherals`]: ../../api/rtic/struct.Peripherals.html
-The example below shows the types of the `core` and `device` fields and
+The example below shows the types of the `core`, `device` and `cs` fields, and
showcases safe access to a `static mut` variable. The `device` field is only
available when the `peripherals` argument is set to `true` (it defaults to
`false`).
@@ -55,12 +49,13 @@ process.
``` console
$ cargo run --example init
-{{#include ../../../../ci/expected/init.run}}```
+{{#include ../../../../ci/expected/init.run}}
+```
## `idle`
A function marked with the `idle` attribute can optionally appear in the
-pseudo-module. This function is used as the special *idle task* and must have
+module. This function is used as the special *idle task* and must have
signature `fn(idle::Context) - > !`.
When present, the runtime will execute the `idle` task after `init`. Unlike
@@ -77,13 +72,17 @@ references that are safe to access.
The example below shows that `idle` runs after `init`.
+**Note:** The `loop {}` in idle cannot be empty as this will crash the microcontroller due to a bug
+in LLVM which miss-optimizes empty loops to a `UDF` instruction in release mode.
+
``` rust
{{#include ../../../../examples/idle.rs}}
```
``` console
$ cargo run --example idle
-{{#include ../../../../ci/expected/idle.run}}```
+{{#include ../../../../ci/expected/idle.run}}
+```
## Hardware tasks
@@ -104,7 +103,8 @@ mut` variables are safe to use within a hardware task.
``` console
$ cargo run --example hardware
-{{#include ../../../../ci/expected/hardware.run}}```
+{{#include ../../../../ci/expected/hardware.run}}
+```
So far all the RTIC applications we have seen look no different than the
applications one can write using only the `cortex-m-rt` crate. From this point
@@ -136,7 +136,8 @@ The following example showcases the priority based scheduling of tasks.
``` console
$ cargo run --example preempt
-{{#include ../../../../ci/expected/preempt.run}}```
+{{#include ../../../../ci/expected/preempt.run}}
+```
Note that the task `gpiob` does *not* preempt task `gpioc` because its priority
is the *same* as `gpioc`'s. However, once `gpioc` terminates the execution of
diff --git a/book/en/src/by-example/new.md b/book/en/src/by-example/new.md
index abcc36de..866a9fa5 100644
--- a/book/en/src/by-example/new.md
+++ b/book/en/src/by-example/new.md
@@ -63,4 +63,5 @@ $ cargo add panic-semihosting
``` console
$ # NOTE: I have uncommented the `runner` option in `.cargo/config`
$ cargo run
-{{#include ../../../../ci/expected/init.run}}```
+{{#include ../../../../ci/expected/init.run}}
+```
diff --git a/book/en/src/by-example/resources.md b/book/en/src/by-example/resources.md
index b9e92d1e..d082dfc1 100644
--- a/book/en/src/by-example/resources.md
+++ b/book/en/src/by-example/resources.md
@@ -4,11 +4,13 @@ The framework provides an abstraction to share data between any of the contexts
we saw in the previous section (task handlers, `init` and `idle`): resources.
Resources are data visible only to functions declared within the `#[app]`
-pseudo-module. The framework gives the user complete control over which context
+module. The framework gives the user complete control over which context
can access which resource.
All resources are declared as a single `struct` within the `#[app]`
-pseudo-module. Each field in the structure corresponds to a different resource.
+module. Each field in the structure corresponds to a different resource.
+The `struct` must be annotated with the following attribute: `#[resources]`.
+
Resources can optionally be given an initial value using the `#[init]`
attribute. Resources that are not given an initial value are referred to as
*late* resources and are covered in more detail in a follow-up section in this
@@ -29,7 +31,8 @@ access to a resource named `shared`.
``` console
$ cargo run --example resource
-{{#include ../../../../ci/expected/resource.run}}```
+{{#include ../../../../ci/expected/resource.run}}
+```
Note that the `shared` resource cannot be accessed from `idle`. Attempting to do
so results in a compile error.
@@ -71,7 +74,8 @@ lowest priority handler.
``` console
$ cargo run --example lock
-{{#include ../../../../ci/expected/lock.run}}```
+{{#include ../../../../ci/expected/lock.run}}
+```
## Late resources
@@ -97,7 +101,8 @@ the consumer resource.
``` console
$ cargo run --example late
-{{#include ../../../../ci/expected/late.run}}```
+{{#include ../../../../ci/expected/late.run}}
+```
## Only shared access
@@ -127,4 +132,5 @@ any kind of lock.
``` console
$ cargo run --example only-shared-access
-{{#include ../../../../ci/expected/only-shared-access.run}}```
+{{#include ../../../../ci/expected/only-shared-access.run}}
+```
diff --git a/book/en/src/by-example/tasks.md b/book/en/src/by-example/tasks.md
index d0b5acb9..ba164048 100644
--- a/book/en/src/by-example/tasks.md
+++ b/book/en/src/by-example/tasks.md
@@ -25,7 +25,8 @@ priorities. The three software tasks are mapped to 2 interrupts handlers.
``` console
$ cargo run --example task
-{{#include ../../../../ci/expected/task.run}}```
+{{#include ../../../../ci/expected/task.run}}
+```
## Message passing
@@ -41,7 +42,8 @@ The example below showcases three tasks, two of them expect a message.
``` console
$ cargo run --example message
-{{#include ../../../../ci/expected/message.run}}```
+{{#include ../../../../ci/expected/message.run}}
+```
## Capacity
@@ -63,7 +65,8 @@ fail (panic).
``` console
$ cargo run --example capacity
-{{#include ../../../../ci/expected/capacity.run}}```
+{{#include ../../../../ci/expected/capacity.run}}
+```
## Error handling
@@ -92,7 +95,7 @@ following snippet:
``` rust
#[rtic::app(..)]
-const APP: () = {
+mod app {
#[init(spawn = [foo, bar])]
fn init(cx: init::Context) {
cx.spawn.foo().unwrap();
@@ -113,5 +116,5 @@ const APP: () = {
fn bar(cx: bar::Context, payload: i32) {
// ..
}
-};
+}
```
diff --git a/book/en/src/by-example/tips.md b/book/en/src/by-example/tips.md
index b191b9da..d8264c90 100644
--- a/book/en/src/by-example/tips.md
+++ b/book/en/src/by-example/tips.md
@@ -24,7 +24,8 @@ Here's one such example:
``` console
$ cargo run --example generics
-{{#include ../../../../ci/expected/generics.run}}```
+{{#include ../../../../ci/expected/generics.run}}
+```
Using generics also lets you change the static priorities of tasks during
development without having to rewrite a bunch code every time.
@@ -47,7 +48,8 @@ the program has been compiled using the `dev` profile.
$ cargo run --example cfg --release
$ cargo run --example cfg
-{{#include ../../../../ci/expected/cfg.run}}```
+{{#include ../../../../ci/expected/cfg.run}}
+```
## Running tasks from RAM
@@ -78,7 +80,8 @@ Running this program produces the expected output.
``` console
$ cargo run --example ramfunc
-{{#include ../../../../ci/expected/ramfunc.run}}```
+{{#include ../../../../ci/expected/ramfunc.run}}
+```
One can look at the output of `cargo-nm` to confirm that `bar` ended in RAM
(`0x2000_0000`), whereas `foo` ended in Flash (`0x0000_0000`).
@@ -115,7 +118,8 @@ Here's an example where `heapless::Pool` is used to "box" buffers of 128 bytes.
```
``` console
$ cargo run --example pool
-{{#include ../../../../ci/expected/pool.run}}```
+{{#include ../../../../ci/expected/pool.run}}
+```
## Inspecting the expanded code
@@ -139,7 +143,7 @@ $ tail target/rtic-expansion.rs
``` rust
#[doc = r" Implementation details"]
-const APP: () = {
+mod app {
#[doc = r" Always include the device crate which contains the vector table"]
use lm3s6965 as _;
#[no_mangle]
@@ -152,7 +156,7 @@ const APP: () = {
rtic::export::wfi()
}
}
-};
+}
```
Or, you can use the [`cargo-expand`] sub-command. This sub-command will expand
diff --git a/book/en/src/by-example/types-send-sync.md b/book/en/src/by-example/types-send-sync.md
index 41cd9ba9..9cdb8894 100644
--- a/book/en/src/by-example/types-send-sync.md
+++ b/book/en/src/by-example/types-send-sync.md
@@ -1,6 +1,6 @@
# Types, Send and Sync
-Every function within the `APP` pseudo-module has a `Context` structure as its
+Every function within the `app` module has a `Context` structure as its
first parameter. All the fields of these structures have predictable,
non-anonymous types so you can write plain functions that take them as arguments.
diff --git a/book/en/src/heterogeneous.md b/book/en/src/heterogeneous.md
deleted file mode 100644
index d2c3d6c5..00000000
--- a/book/en/src/heterogeneous.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# Heterogeneous multi-core support
-
-This section covers the *experimental* heterogeneous multi-core support provided
-by RTIC behind the `heterogeneous` Cargo feature.
-
-**Content coming soon**
diff --git a/book/en/src/homogeneous.md b/book/en/src/homogeneous.md
deleted file mode 100644
index bcf6d2be..00000000
--- a/book/en/src/homogeneous.md
+++ /dev/null
@@ -1,6 +0,0 @@
-# Homogeneous multi-core support
-
-This section covers the *experimental* homogeneous multi-core support provided
-by RTIC behind the `homogeneous` Cargo feature.
-
-**Content coming soon**
diff --git a/book/en/src/internals/access.md b/book/en/src/internals/access.md
index 6433707e..3894470c 100644
--- a/book/en/src/internals/access.md
+++ b/book/en/src/internals/access.md
@@ -15,7 +15,7 @@ To achieve the fine-grained access control where tasks can only access the
static variables (resources) that they have specified in their RTIC attribute
the RTIC framework performs a source code level transformation. This
transformation consists of placing the resources (static variables) specified by
-the user *inside* a `const` item and the user code *outside* the `const` item.
+the user *inside* a module and the user code *outside* the module.
This makes it impossible for the user code to refer to these static variables.
Access to the resources is then given to each task using a `Resources` struct
@@ -29,7 +29,7 @@ happens behind the scenes:
``` rust
#[rtic::app(device = ..)]
-const APP: () = {
+mod app {
static mut X: u64: 0;
static mut Y: bool: 0;
@@ -49,7 +49,7 @@ const APP: () = {
}
// ..
-};
+}
```
The framework produces codes like this:
@@ -103,8 +103,8 @@ pub mod bar {
}
/// Implementation details
-const APP: () = {
- // everything inside this `const` item is hidden from user code
+mod app {
+ // everything inside this module is hidden from user code
static mut X: u64 = 0;
static mut Y: bool = 0;
@@ -154,5 +154,5 @@ const APP: () = {
// ..
});
}
-};
+}
```
diff --git a/book/en/src/internals/ceilings.md b/book/en/src/internals/ceilings.md
index 49d248ad..07bd0add 100644
--- a/book/en/src/internals/ceilings.md
+++ b/book/en/src/internals/ceilings.md
@@ -28,7 +28,7 @@ An example to illustrate the ceiling analysis:
``` rust
#[rtic::app(device = ..)]
-const APP: () = {
+mod app {
struct Resources {
// accessed by `foo` (prio = 1) and `bar` (prio = 2)
// -> CEILING = 2
@@ -80,5 +80,5 @@ const APP: () = {
}
// ..
-};
+}
```
diff --git a/book/en/src/internals/critical-sections.md b/book/en/src/internals/critical-sections.md
index f95a5a7a..a064ad09 100644
--- a/book/en/src/internals/critical-sections.md
+++ b/book/en/src/internals/critical-sections.md
@@ -32,7 +32,7 @@ The example below shows the different types handed out to each task:
``` rust
#[rtic::app(device = ..)]
-const APP: () = {
+mut app {
struct Resources {
#[init(0)]
x: u64,
@@ -57,7 +57,7 @@ const APP: () = {
}
// ..
-};
+}
```
Now let's see how these types are created by the framework.
@@ -99,7 +99,7 @@ pub mod bar {
}
}
-const APP: () = {
+mod app {
static mut x: u64 = 0;
impl rtic::Mutex for resources::x {
@@ -129,7 +129,7 @@ const APP: () = {
// ..
})
}
-};
+}
```
## `lock`
@@ -225,7 +225,7 @@ Consider this program:
``` rust
#[rtic::app(device = ..)]
-const APP: () = {
+mod app {
struct Resources {
#[init(0)]
x: u64,
@@ -277,7 +277,7 @@ const APP: () = {
}
// ..
-};
+}
```
The code generated by the framework looks like this:
@@ -315,7 +315,7 @@ pub mod foo {
}
}
-const APP: () = {
+mod app {
use cortex_m::register::basepri;
#[no_mangle]
@@ -368,7 +368,7 @@ const APP: () = {
}
// repeat for resource `y`
-};
+}
```
At the end the compiler will optimize the function `foo` into something like
@@ -430,7 +430,7 @@ handler through preemption. This is best observed in the following example:
``` rust
#[rtic::app(device = ..)]
-const APP: () = {
+mod app {
struct Resources {
#[init(0)]
x: u64,
@@ -484,7 +484,7 @@ const APP: () = {
// ..
}
-};
+}
```
IMPORTANT: let's say we *forget* to roll back `BASEPRI` in `UART1` -- this would
@@ -493,7 +493,7 @@ be a bug in the RTIC code generator.
``` rust
// code generated by RTIC
-const APP: () = {
+mod app {
// ..
#[no_mangle]
@@ -513,7 +513,7 @@ const APP: () = {
// BUG: FORGOT to roll back the BASEPRI to the snapshot value we took before
basepri::write(initial);
}
-};
+}
```
The consequence is that `idle` will run at a dynamic priority of `2` and in fact
diff --git a/book/en/src/internals/interrupt-configuration.md b/book/en/src/internals/interrupt-configuration.md
index 278707c0..7aec9c9f 100644
--- a/book/en/src/internals/interrupt-configuration.md
+++ b/book/en/src/internals/interrupt-configuration.md
@@ -13,7 +13,7 @@ This example gives you an idea of the code that the RTIC framework runs:
``` rust
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
fn init(c: init::Context) {
// .. user code ..
@@ -28,7 +28,7 @@ const APP: () = {
fn foo(c: foo::Context) {
// .. user code ..
}
-};
+}
```
The framework generates an entry point that looks like this:
diff --git a/book/en/src/internals/late-resources.md b/book/en/src/internals/late-resources.md
index ad2a5e51..f3a0b0ae 100644
--- a/book/en/src/internals/late-resources.md
+++ b/book/en/src/internals/late-resources.md
@@ -10,7 +10,7 @@ initialize late resources.
``` rust
#[rtic::app(device = ..)]
-const APP: () = {
+mod app {
struct Resources {
x: Thing,
}
@@ -34,7 +34,7 @@ const APP: () = {
}
// ..
-};
+}
```
The code generated by the framework looks like this:
@@ -69,7 +69,7 @@ pub mod foo {
}
/// Implementation details
-const APP: () = {
+mod app {
// uninitialized static
static mut x: MaybeUninit<Thing> = MaybeUninit::uninit();
@@ -101,7 +101,7 @@ const APP: () = {
// ..
})
}
-};
+}
```
An important detail here is that `interrupt::enable` behaves like a *compiler
diff --git a/book/en/src/internals/non-reentrancy.md b/book/en/src/internals/non-reentrancy.md
index 0b0e4a73..17b34d0c 100644
--- a/book/en/src/internals/non-reentrancy.md
+++ b/book/en/src/internals/non-reentrancy.md
@@ -12,7 +12,7 @@ are discouraged from directly invoking an interrupt handler.
``` rust
#[rtic::app(device = ..)]
-const APP: () = {
+mod app {
#[init]
fn init(c: init::Context) { .. }
@@ -39,7 +39,7 @@ const APP: () = {
// in aliasing of the static variable `X`
unsafe { UART0() }
}
-};
+}
```
The RTIC framework must generate the interrupt handler code that calls the user
@@ -57,7 +57,7 @@ fn bar(c: bar::Context) {
// .. user code ..
}
-const APP: () = {
+mod app {
// everything in this block is not visible to user code
#[no_mangle]
@@ -69,7 +69,7 @@ const APP: () = {
unsafe fn USART1() {
bar(..);
}
-};
+}
```
## By hardware
diff --git a/book/en/src/internals/tasks.md b/book/en/src/internals/tasks.md
index 995a8857..a533dc0c 100644
--- a/book/en/src/internals/tasks.md
+++ b/book/en/src/internals/tasks.md
@@ -28,7 +28,7 @@ Consider this example:
``` rust
#[rtic::app(device = ..)]
-const APP: () = {
+mod app {
// ..
#[interrupt(binds = UART0, priority = 2, spawn = [bar, baz])]
@@ -51,7 +51,7 @@ const APP: () = {
extern "C" {
fn UART1();
}
-};
+}
```
The framework produces the following task dispatcher which consists of an
@@ -62,7 +62,7 @@ fn bar(c: bar::Context) {
// .. user code ..
}
-const APP: () = {
+mod app {
use heapless::spsc::Queue;
use cortex_m::register::basepri;
@@ -110,7 +110,7 @@ const APP: () = {
// BASEPRI invariant
basepri::write(snapshot);
}
-};
+}
```
## Spawning a task
@@ -144,7 +144,7 @@ mod foo {
}
}
-const APP: () = {
+mod app {
// ..
// Priority ceiling for the producer endpoint of the `RQ1`
@@ -194,7 +194,7 @@ const APP: () = {
}
}
}
-};
+}
```
Using `bar_FQ` to limit the number of `bar` tasks that can be spawned may seem
@@ -211,7 +211,7 @@ fn baz(c: baz::Context, input: u64) {
// .. user code ..
}
-const APP: () = {
+mod app {
// ..
// Now we show the full contents of the `Ready` struct
@@ -263,13 +263,13 @@ const APP: () = {
}
}
}
-};
+}
```
And now let's look at the real implementation of the task dispatcher:
``` rust
-const APP: () = {
+mod app {
// ..
#[no_mangle]
@@ -304,7 +304,7 @@ const APP: () = {
// BASEPRI invariant
basepri::write(snapshot);
}
-};
+}
```
`INPUTS` plus `FQ`, the free queue, is effectively a memory pool. However,
@@ -357,7 +357,7 @@ Consider the following example:
``` rust
#[rtic::app(device = ..)]
-const APP: () = {
+mod app {
#[idle(spawn = [foo, bar])]
fn idle(c: idle::Context) -> ! {
// ..
@@ -382,7 +382,7 @@ const APP: () = {
fn quux(c: quux::Context) {
// ..
}
-};
+}
```
This is how the ceiling analysis would go:
diff --git a/book/en/src/internals/timer-queue.md b/book/en/src/internals/timer-queue.md
index 0eba1069..fcd345c5 100644
--- a/book/en/src/internals/timer-queue.md
+++ b/book/en/src/internals/timer-queue.md
@@ -12,7 +12,7 @@ Let's see how this in implemented in code. Consider the following program:
``` rust
#[rtic::app(device = ..)]
-const APP: () = {
+mod app {
// ..
#[task(capacity = 2, schedule = [foo])]
@@ -24,7 +24,7 @@ const APP: () = {
extern "C" {
fn UART0();
}
-};
+}
```
## `schedule`
@@ -46,7 +46,7 @@ mod foo {
}
}
-const APP: () = {
+mod app {
type Instant = <path::to::user::monotonic::timer as rtic::Monotonic>::Instant;
// all tasks that can be `schedule`-d
@@ -100,7 +100,7 @@ const APP: () = {
}
}
}
-};
+}
```
This looks very similar to the `Spawn` implementation. In fact, the same
@@ -123,7 +123,7 @@ is up.
Let's see the associated code.
``` rust
-const APP: () = {
+mod app {
#[no_mangle]
fn SysTick() {
const PRIORITY: u8 = 1;
@@ -146,7 +146,7 @@ const APP: () = {
}
}
}
-};
+}
```
This looks similar to a task dispatcher except that instead of running the
@@ -197,7 +197,7 @@ able to insert the task in the timer queue; this lets us omit runtime checks.
## System timer priority
-The priority of the system timer can't set by the user; it is chosen by the
+The priority of the system timer can't be set by the user; it is chosen by the
framework. To ensure that lower priority tasks don't prevent higher priority
tasks from running we choose the priority of the system timer to be the maximum
of all the `schedule`-able tasks.
@@ -222,7 +222,7 @@ To illustrate, consider the following example:
``` rust
#[rtic::app(device = ..)]
-const APP: () = {
+mod app {
#[task(priority = 3, spawn = [baz])]
fn foo(c: foo::Context) {
// ..
@@ -237,7 +237,7 @@ const APP: () = {
fn baz(c: baz::Context) {
// ..
}
-};
+}
```
The ceiling analysis would go like this:
@@ -246,7 +246,7 @@ The ceiling analysis would go like this:
`SysTick` must run at the highest priority between these two, that is `3`.
- `foo::Spawn` (prio = 3) and `bar::Schedule` (prio = 2) contend over the
- consumer endpoind of `baz_FQ`; this leads to a priority ceiling of `3`.
+ consumer endpoint of `baz_FQ`; this leads to a priority ceiling of `3`.
- `bar::Schedule` (prio = 2) has exclusive access over the consumer endpoint of
`foo_FQ`; thus the priority ceiling of `foo_FQ` is effectively `2`.
@@ -270,7 +270,7 @@ run; this `Instant` is read in the task dispatcher and passed to the user code
as part of the task context.
``` rust
-const APP: () = {
+mod app {
// ..
#[no_mangle]
@@ -303,7 +303,7 @@ const APP: () = {
// BASEPRI invariant
basepri::write(snapshot);
}
-};
+}
```
Conversely, the `spawn` implementation needs to write a value to the `INSTANTS`
@@ -333,7 +333,7 @@ mod foo {
}
}
-const APP: () = {
+mod app {
impl<'a> foo::Spawn<'a> {
/// Spawns the `baz` task
pub fn baz(&self, message: u64) -> Result<(), u64> {
@@ -364,5 +364,5 @@ const APP: () = {
}
}
}
-};
+}
```
diff --git a/book/en/src/migration.md b/book/en/src/migration.md
index 6cca64db..08feb81e 100644
--- a/book/en/src/migration.md
+++ b/book/en/src/migration.md
@@ -1,233 +1,4 @@
-# Migrating from v0.4.x to v0.5.0
+# Migration Guides
-This section covers how to upgrade an application written against RTIC v0.4.x to
-the version v0.5.0 of the framework.
-
-## `Cargo.toml`
-
-First, the version of the `cortex-m-rtic` dependency needs to be updated to
-`"0.5.0"`. The `timer-queue` feature needs to be removed.
-
-
-``` toml
-[dependencies.cortex-m-rtic]
-# change this
-version = "0.4.3"
-
-# into this
-version = "0.5.0"
-
-# and remove this Cargo feature
-features = ["timer-queue"]
-# ^^^^^^^^^^^^^
-```
-
-## `Context` argument
-
-All functions inside the `#[rtic::app]` item need to take as first argument a
-`Context` structure. This `Context` type will contain the variables that were
-magically injected into the scope of the function by version v0.4.x of the
-framework: `resources`, `spawn`, `schedule` -- these variables will become
-fields of the `Context` structure. Each function within the `#[rtic::app]` item
-gets a different `Context` type.
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- // change this
- #[task(resources = [x], spawn = [a], schedule = [b])]
- fn foo() {
- resources.x.lock(|x| /* .. */);
- spawn.a(message);
- schedule.b(baseline);
- }
-
- // into this
- #[task(resources = [x], spawn = [a], schedule = [b])]
- fn foo(mut cx: foo::Context) {
- // ^^^^^^^^^^^^^^^^^^^^
-
- cx.resources.x.lock(|x| /* .. */);
- // ^^^
-
- cx.spawn.a(message);
- // ^^^
-
- cx.schedule.b(message, baseline);
- // ^^^
- }
-
- // change this
- #[init]
- fn init() {
- // ..
- }
-
- // into this
- #[init]
- fn init(cx: init::Context) {
- // ^^^^^^^^^^^^^^^^^
- // ..
- }
-
- // ..
-};
-```
-
-## Resources
-
-The syntax used to declare resources has been changed from `static mut`
-variables to a `struct Resources`.
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- // change this
- static mut X: u32 = 0;
- static mut Y: u32 = (); // late resource
-
- // into this
- struct Resources {
- #[init(0)] // <- initial value
- X: u32, // NOTE: we suggest changing the naming style to `snake_case`
-
- Y: u32, // late resource
- }
-
- // ..
-};
-```
-
-## Device peripherals
-
-If your application was accessing the device peripherals in `#[init]` through
-the `device` variable then you'll need to add `peripherals = true` to the
-`#[rtic::app]` attribute to continue to access the device peripherals through
-the `device` field of the `init::Context` structure.
-
-Change this:
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- #[init]
- fn init() {
- device.SOME_PERIPHERAL.write(something);
- }
-
- // ..
-};
-```
-
-Into this:
-
-``` rust
-#[rtic::app(/* .. */, peripherals = true)]
-// ^^^^^^^^^^^^^^^^^^
-const APP: () = {
- #[init]
- fn init(cx: init::Context) {
- // ^^^^^^^^^^^^^^^^^
- cx.device.SOME_PERIPHERAL.write(something);
- // ^^^
- }
-
- // ..
-};
-```
-
-## `#[interrupt]` and `#[exception]`
-
-The `#[interrupt]` and `#[exception]` attributes have been removed. To declare
-hardware tasks in v0.5.x use the `#[task]` attribute with the `binds` argument.
-
-Change this:
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- // hardware tasks
- #[exception]
- fn SVCall() { /* .. */ }
-
- #[interrupt]
- fn UART0() { /* .. */ }
-
- // software task
- #[task]
- fn foo() { /* .. */ }
-
- // ..
-};
-```
-
-Into this:
-
-``` rust
-#[rtic::app(/* .. */)]
-const APP: () = {
- #[task(binds = SVCall)]
- // ^^^^^^^^^^^^^^
- fn svcall(cx: svcall::Context) { /* .. */ }
- // ^^^^^^ we suggest you use a `snake_case` name here
-
- #[task(binds = UART0)]
- // ^^^^^^^^^^^^^
- fn uart0(cx: uart0::Context) { /* .. */ }
-
- #[task]
- fn foo(cx: foo::Context) { /* .. */ }
-
- // ..
-};
-```
-
-## `schedule`
-
-The `timer-queue` feature has been removed. To use the `schedule` API one must
-first define the monotonic timer the runtime will use using the `monotonic`
-argument of the `#[rtic::app]` attribute. To continue using the cycle counter
-(CYCCNT) as the monotonic timer, and match the behavior of version v0.4.x, add
-the `monotonic = rtic::cyccnt::CYCCNT` argument to the `#[rtic::app]` attribute.
-
-Also, the `Duration` and `Instant` types and the `U32Ext` trait have been moved
-into the `rtic::cyccnt` module. This module is only available on ARMv7-M+
-devices. The removal of the `timer-queue` also brings back the `DWT` peripheral
-inside the core peripherals struct, this will need to be enabled by the application
-inside `init`.
-
-Change this:
-
-``` rust
-use rtic::{Duration, Instant, U32Ext};
-
-#[rtic::app(/* .. */)]
-const APP: () = {
- #[task(schedule = [b])]
- fn a() {
- // ..
- }
-};
-```
-
-Into this:
-
-``` rust
-use rtic::cyccnt::{Duration, Instant, U32Ext};
-// ^^^^^^^^
-
-#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)]
-// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-const APP: () = {
- #[init]
- fn init(cx: init::Context) {
- cx.core.DWT.enable_cycle_counter();
- // optional, configure the DWT run without a debugger connected
- cx.core.DCB.enable_trace();
- }
- #[task(schedule = [b])]
- fn a(cx: a::Context) {
- // ..
- }
-};
-```
+This section describes how to migrate between different version of RTIC.
+It also acts as a comparing reference between versions.
diff --git a/book/en/src/migration_rtic.md b/book/en/src/migration/migration_rtic.md
index 555f1bb7..555f1bb7 100644
--- a/book/en/src/migration_rtic.md
+++ b/book/en/src/migration/migration_rtic.md
diff --git a/book/en/src/migration/migration_v4.md b/book/en/src/migration/migration_v4.md
new file mode 100644
index 00000000..2c4e3ade
--- /dev/null
+++ b/book/en/src/migration/migration_v4.md
@@ -0,0 +1,232 @@
+# Migrating from v0.4.x to v0.5.0
+
+This section covers how to upgrade an application written against RTIC v0.4.x to
+the version v0.5.0 of the framework.
+
+### `Cargo.toml`
+
+First, the version of the `cortex-m-rtic` dependency needs to be updated to
+`"0.5.0"`. The `timer-queue` feature needs to be removed.
+
+``` toml
+[dependencies.cortex-m-rtic]
+# change this
+version = "0.4.3"
+
+# into this
+version = "0.5.0"
+
+# and remove this Cargo feature
+features = ["timer-queue"]
+# ^^^^^^^^^^^^^
+```
+
+### `Context` argument
+
+All functions inside the `#[rtic::app]` item need to take as first argument a
+`Context` structure. This `Context` type will contain the variables that were
+magically injected into the scope of the function by version v0.4.x of the
+framework: `resources`, `spawn`, `schedule` -- these variables will become
+fields of the `Context` structure. Each function within the `#[rtic::app]` item
+gets a different `Context` type.
+
+``` rust
+#[rtic::app(/* .. */)]
+const APP: () = {
+ // change this
+ #[task(resources = [x], spawn = [a], schedule = [b])]
+ fn foo() {
+ resources.x.lock(|x| /* .. */);
+ spawn.a(message);
+ schedule.b(baseline);
+ }
+
+ // into this
+ #[task(resources = [x], spawn = [a], schedule = [b])]
+ fn foo(mut cx: foo::Context) {
+ // ^^^^^^^^^^^^^^^^^^^^
+
+ cx.resources.x.lock(|x| /* .. */);
+ // ^^^
+
+ cx.spawn.a(message);
+ // ^^^
+
+ cx.schedule.b(message, baseline);
+ // ^^^
+ }
+
+ // change this
+ #[init]
+ fn init() {
+ // ..
+ }
+
+ // into this
+ #[init]
+ fn init(cx: init::Context) {
+ // ^^^^^^^^^^^^^^^^^
+ // ..
+ }
+
+ // ..
+};
+```
+
+### Resources
+
+The syntax used to declare resources has been changed from `static mut`
+variables to a `struct Resources`.
+
+``` rust
+#[rtic::app(/* .. */)]
+const APP: () = {
+ // change this
+ static mut X: u32 = 0;
+ static mut Y: u32 = (); // late resource
+
+ // into this
+ struct Resources {
+ #[init(0)] // <- initial value
+ X: u32, // NOTE: we suggest changing the naming style to `snake_case`
+
+ Y: u32, // late resource
+ }
+
+ // ..
+};
+```
+
+### Device peripherals
+
+If your application was accessing the device peripherals in `#[init]` through
+the `device` variable then you'll need to add `peripherals = true` to the
+`#[rtic::app]` attribute to continue to access the device peripherals through
+the `device` field of the `init::Context` structure.
+
+Change this:
+
+``` rust
+#[rtic::app(/* .. */)]
+const APP: () = {
+ #[init]
+ fn init() {
+ device.SOME_PERIPHERAL.write(something);
+ }
+
+ // ..
+};
+```
+
+Into this:
+
+``` rust
+#[rtic::app(/* .. */, peripherals = true)]
+// ^^^^^^^^^^^^^^^^^^
+const APP: () = {
+ #[init]
+ fn init(cx: init::Context) {
+ // ^^^^^^^^^^^^^^^^^
+ cx.device.SOME_PERIPHERAL.write(something);
+ // ^^^
+ }
+
+ // ..
+};
+```
+
+### `#[interrupt]` and `#[exception]`
+
+The `#[interrupt]` and `#[exception]` attributes have been removed. To declare
+hardware tasks in v0.5.x use the `#[task]` attribute with the `binds` argument.
+
+Change this:
+
+``` rust
+#[rtic::app(/* .. */)]
+const APP: () = {
+ // hardware tasks
+ #[exception]
+ fn SVCall() { /* .. */ }
+
+ #[interrupt]
+ fn UART0() { /* .. */ }
+
+ // software task
+ #[task]
+ fn foo() { /* .. */ }
+
+ // ..
+};
+```
+
+Into this:
+
+``` rust
+#[rtic::app(/* .. */)]
+const APP: () = {
+ #[task(binds = SVCall)]
+ // ^^^^^^^^^^^^^^
+ fn svcall(cx: svcall::Context) { /* .. */ }
+ // ^^^^^^ we suggest you use a `snake_case` name here
+
+ #[task(binds = UART0)]
+ // ^^^^^^^^^^^^^
+ fn uart0(cx: uart0::Context) { /* .. */ }
+
+ #[task]
+ fn foo(cx: foo::Context) { /* .. */ }
+
+ // ..
+};
+```
+
+### `schedule`
+
+The `timer-queue` feature has been removed. To use the `schedule` API one must
+first define the monotonic timer the runtime will use using the `monotonic`
+argument of the `#[rtic::app]` attribute. To continue using the cycle counter
+(CYCCNT) as the monotonic timer, and match the behavior of version v0.4.x, add
+the `monotonic = rtic::cyccnt::CYCCNT` argument to the `#[rtic::app]` attribute.
+
+Also, the `Duration` and `Instant` types and the `U32Ext` trait have been moved
+into the `rtic::cyccnt` module. This module is only available on ARMv7-M+
+devices. The removal of the `timer-queue` also brings back the `DWT` peripheral
+inside the core peripherals struct, this will need to be enabled by the application
+inside `init`.
+
+Change this:
+
+``` rust
+use rtic::{Duration, Instant, U32Ext};
+
+#[rtic::app(/* .. */)]
+const APP: () = {
+ #[task(schedule = [b])]
+ fn a() {
+ // ..
+ }
+};
+```
+
+Into this:
+
+``` rust
+use rtic::cyccnt::{Duration, Instant, U32Ext};
+// ^^^^^^^^
+
+#[rtic::app(/* .. */, monotonic = rtic::cyccnt::CYCCNT)]
+// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+const APP: () = {
+ #[init]
+ fn init(cx: init::Context) {
+ cx.core.DWT.enable_cycle_counter();
+ // optional, configure the DWT run without a debugger connected
+ cx.core.DCB.enable_trace();
+ }
+ #[task(schedule = [b])]
+ fn a(cx: a::Context) {
+ // ..
+ }
+};
+```
diff --git a/book/en/src/migration/migration_v5.md b/book/en/src/migration/migration_v5.md
new file mode 100644
index 00000000..749ddecd
--- /dev/null
+++ b/book/en/src/migration/migration_v5.md
@@ -0,0 +1,96 @@
+# Migrating from v0.5.x to v0.6.0
+
+This section describes how to upgrade from v0.5.x to v0.6.0 of the RTIC framework.
+
+### `Cargo.toml` - version bump
+
+Change the version of `cortex-m-rtic` to `"0.6.0"`.
+
+### Module instead of Const
+
+With the support of attributes on modules the `const APP` workaround is not needed.
+
+Change
+
+``` rust
+#[rtic::app(/* .. */)]
+const APP: () = {
+ [code here]
+};
+```
+
+into
+
+``` rust
+#[rtic::app(/* .. */)]
+mod app {
+ [code here]
+}
+```
+
+Now that a regular Rust module is used it means it is possible to have custom
+user code within that module.
+Additionally, it means that `use`-statements for resources etc may be required.
+
+### Init always returns late resources
+
+In order to make the API more symmetric the #[init]-task always returns a late resource.
+
+From this:
+
+``` rust
+#[rtic::app(device = lm3s6965)]
+mod app {
+ #[init]
+ fn init(_: init::Context) {
+ rtic::pend(Interrupt::UART0);
+ }
+ [more code]
+}
+```
+
+to this:
+
+``` rust
+#[rtic::app(device = lm3s6965)]
+mod app {
+ #[init]
+ fn init(_: init::Context) -> init::LateResources {
+ rtic::pend(Interrupt::UART0);
+
+ init::LateResources {}
+ }
+ [more code]
+}
+```
+
+### Resources struct - #[resources]
+
+Previously the RTIC resources had to be in in a struct named exactly "Resources":
+
+``` rust
+struct Resources {
+ // Resources defined in here
+}
+```
+
+With RTIC v0.6.0 the resources struct is annotated similarly like
+`#[task]`, `#[init]`, `#[idle]`: with an attribute `#[resources]`
+
+``` rust
+#[resources]
+struct Resources {
+ // Resources defined in here
+}
+```
+
+In fact, the name of the struct is now up to the developer:
+
+``` rust
+#[resources]
+struct whateveryouwant {
+ // Resources defined in here
+}
+```
+
+would work equally well.
diff --git a/book/en/src/preface.md b/book/en/src/preface.md
index 419f067e..041b3bd4 100644
--- a/book/en/src/preface.md
+++ b/book/en/src/preface.md
@@ -13,8 +13,10 @@ There is a translation of this book in [Russian].
[Russian]: ../ru/index.html
-This is the documentation of v0.5.x of RTIC; for the documentation of version
-v0.4.x go [here](/0.4).
+This is the documentation of v0.6.x of RTIC; for the documentation of version
+
+* v0.5.x go [here](/0.5).
+* v0.4.x go [here](/0.4).
{{#include ../../../README.md:7:46}}
diff --git a/examples/baseline.rs b/examples/baseline.rs
index f46b273d..3ab40dbb 100644
--- a/examples/baseline.rs
+++ b/examples/baseline.rs
@@ -11,15 +11,17 @@ use panic_semihosting as _;
// NOTE: does NOT properly work on QEMU
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
-const APP: () = {
+mod app {
#[init(spawn = [foo])]
- fn init(cx: init::Context) {
+ fn init(cx: init::Context) -> init::LateResources {
// omitted: initialization of `CYCCNT`
hprintln!("init(baseline = {:?})", cx.start).unwrap();
// `foo` inherits the baseline of `init`: `Instant(0)`
cx.spawn.foo().unwrap();
+
+ init::LateResources {}
}
#[task(schedule = [foo])]
@@ -51,4 +53,4 @@ const APP: () = {
extern "C" {
fn SSI0();
}
-};
+}
diff --git a/examples/binds.rs b/examples/binds.rs
index faf315f4..42010ae2 100644
--- a/examples/binds.rs
+++ b/examples/binds.rs
@@ -11,12 +11,14 @@ use panic_semihosting as _;
// `examples/interrupt.rs` rewritten to use `binds`
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
hprintln!("init").unwrap();
+
+ init::LateResources {}
}
#[idle]
@@ -27,7 +29,9 @@ const APP: () = {
debug::exit(debug::EXIT_SUCCESS);
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
#[task(binds = UART0)]
@@ -43,4 +47,4 @@ const APP: () = {
)
.unwrap();
}
-};
+}
diff --git a/examples/capacity.rs b/examples/capacity.rs
index 00cec344..ba8b15b0 100644
--- a/examples/capacity.rs
+++ b/examples/capacity.rs
@@ -10,10 +10,12 @@ use lm3s6965::Interrupt;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
+
+ init::LateResources {}
}
#[task(binds = UART0, spawn = [foo, bar])]
@@ -44,4 +46,4 @@ const APP: () = {
extern "C" {
fn SSI0();
}
-};
+}
diff --git a/examples/cfg.rs b/examples/cfg.rs
index 02b39e34..d49f54c7 100644
--- a/examples/cfg.rs
+++ b/examples/cfg.rs
@@ -11,7 +11,8 @@ use cortex_m_semihosting::hprintln;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ #[resources]
struct Resources {
#[cfg(debug_assertions)] // <- `true` when using the `dev` profile
#[init(0)]
@@ -19,16 +20,20 @@ const APP: () = {
}
#[init(spawn = [foo])]
- fn init(cx: init::Context) {
+ fn init(cx: init::Context) -> init::LateResources {
cx.spawn.foo().unwrap();
cx.spawn.foo().unwrap();
+
+ init::LateResources {}
}
#[idle]
fn idle(_: idle::Context) -> ! {
debug::exit(debug::EXIT_SUCCESS);
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
#[task(capacity = 2, resources = [count], spawn = [log])]
@@ -64,4 +69,4 @@ const APP: () = {
fn SSI0();
fn QEI0();
}
-};
+}
diff --git a/examples/destructure.rs b/examples/destructure.rs
index 1756bd9e..e7c53237 100644
--- a/examples/destructure.rs
+++ b/examples/destructure.rs
@@ -10,7 +10,8 @@ use lm3s6965::Interrupt;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ #[resources]
struct Resources {
// Some resources to work with
#[init(0)]
@@ -22,9 +23,11 @@ const APP: () = {
}
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
rtic::pend(Interrupt::UART1);
+
+ init::LateResources {}
}
// Direct destructure
@@ -44,4 +47,4 @@ const APP: () = {
hprintln!("UART0: a = {}, b = {}, c = {}", a, b, c).unwrap();
}
-};
+}
diff --git a/examples/double_schedule.rs b/examples/double_schedule.rs
new file mode 100644
index 00000000..b1b78b80
--- /dev/null
+++ b/examples/double_schedule.rs
@@ -0,0 +1,39 @@
+//! examples/double_schedule.rs
+
+#![deny(unsafe_code)]
+#![deny(warnings)]
+#![no_main]
+#![no_std]
+
+use panic_semihosting as _;
+use rtic::cyccnt::U32Ext;
+
+#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
+mod app {
+
+ #[resources]
+ struct Resources {
+ nothing: (),
+ }
+
+ #[init(spawn = [task1])]
+ fn init(cx: init::Context) -> init::LateResources {
+ cx.spawn.task1().ok();
+
+ init::LateResources { nothing: () }
+ }
+
+ #[task(schedule = [task2])]
+ fn task1(_cx: task1::Context) {
+ _cx.schedule.task2(_cx.scheduled + 100.cycles()).ok();
+ }
+
+ #[task(schedule = [task1])]
+ fn task2(_cx: task2::Context) {
+ _cx.schedule.task1(_cx.scheduled + 100.cycles()).ok();
+ }
+
+ extern "C" {
+ fn SSI0();
+ }
+}
diff --git a/examples/generics.rs b/examples/generics.rs
index 40ab81ac..3107dd11 100644
--- a/examples/generics.rs
+++ b/examples/generics.rs
@@ -11,16 +11,19 @@ use panic_semihosting as _;
use rtic::{Exclusive, Mutex};
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ #[resources]
struct Resources {
#[init(0)]
shared: u32,
}
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
rtic::pend(Interrupt::UART1);
+
+ init::LateResources {}
}
#[task(binds = UART0, resources = [shared])]
@@ -49,7 +52,7 @@ const APP: () = {
// second argument has type `Exclusive<u32>`
advance(STATE, Exclusive(c.resources.shared));
}
-};
+}
// the second parameter is generic: it can be any type that implements the `Mutex` trait
fn advance(state: &mut u32, mut shared: impl Mutex<T = u32>) {
diff --git a/examples/hardware.rs b/examples/hardware.rs
index 9f1c664e..f6a2d375 100644
--- a/examples/hardware.rs
+++ b/examples/hardware.rs
@@ -10,14 +10,16 @@ use lm3s6965::Interrupt;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
// Pends the UART0 interrupt but its handler won't run until *after*
// `init` returns because interrupts are disabled
rtic::pend(Interrupt::UART0); // equivalent to NVIC::pend
hprintln!("init").unwrap();
+
+ init::LateResources {}
}
#[idle]
@@ -30,7 +32,9 @@ const APP: () = {
debug::exit(debug::EXIT_SUCCESS);
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
#[task(binds = UART0)]
@@ -47,4 +51,4 @@ const APP: () = {
)
.unwrap();
}
-};
+}
diff --git a/examples/idle.rs b/examples/idle.rs
index c09af922..58c3c87d 100644
--- a/examples/idle.rs
+++ b/examples/idle.rs
@@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
hprintln!("init").unwrap();
+
+ init::LateResources {}
}
#[idle]
@@ -26,6 +28,8 @@ const APP: () = {
debug::exit(debug::EXIT_SUCCESS);
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
-};
+}
diff --git a/examples/init.rs b/examples/init.rs
index 315969f0..6ac284a1 100644
--- a/examples/init.rs
+++ b/examples/init.rs
@@ -9,9 +9,9 @@ use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _;
#[rtic::app(device = lm3s6965, peripherals = true)]
-const APP: () = {
+mod app {
#[init]
- fn init(cx: init::Context) {
+ fn init(cx: init::Context) -> init::LateResources {
static mut X: u32 = 0;
// Cortex-M peripherals
@@ -23,8 +23,14 @@ const APP: () = {
// Safe access to local `static mut` variable
let _x: &'static mut u32 = X;
+ // Access to the critical section token,
+ // to indicate that this is a critical seciton
+ let _cs_token: bare_metal::CriticalSection = cx.cs;
+
hprintln!("init").unwrap();
debug::exit(debug::EXIT_SUCCESS);
+
+ init::LateResources {}
}
-};
+}
diff --git a/examples/late.rs b/examples/late.rs
index 60b9be00..761c68f5 100644
--- a/examples/late.rs
+++ b/examples/late.rs
@@ -15,8 +15,13 @@ use lm3s6965::Interrupt;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ use heapless::{
+ consts::*,
+ spsc::{Consumer, Producer},
+ };
// Late resources
+ #[resources]
struct Resources {
p: Producer<'static, u32, U4>,
c: Consumer<'static, u32, U4>,
@@ -49,4 +54,4 @@ const APP: () = {
fn uart0(c: uart0::Context) {
c.resources.p.enqueue(42).unwrap();
}
-};
+}
diff --git a/examples/lock.rs b/examples/lock.rs
index 5e3bce25..669b1aed 100644
--- a/examples/lock.rs
+++ b/examples/lock.rs
@@ -10,15 +10,18 @@ use lm3s6965::Interrupt;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ #[resources]
struct Resources {
#[init(0)]
shared: u32,
}
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::GPIOA);
+
+ init::LateResources {}
}
// when omitted priority is assumed to be `1`
@@ -59,4 +62,4 @@ const APP: () = {
fn gpioc(_: gpioc::Context) {
hprintln!("C").unwrap();
}
-};
+}
diff --git a/examples/message.rs b/examples/message.rs
index 596f2449..f9736728 100644
--- a/examples/message.rs
+++ b/examples/message.rs
@@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init(spawn = [foo])]
- fn init(c: init::Context) {
+ fn init(c: init::Context) -> init::LateResources {
c.spawn.foo(/* no message */).unwrap();
+
+ init::LateResources {}
}
#[task(spawn = [bar])]
@@ -49,4 +51,4 @@ const APP: () = {
extern "C" {
fn SSI0();
}
-};
+}
diff --git a/examples/not-send.rs b/examples/not-send.rs
index 16a874dc..18071fc5 100644
--- a/examples/not-send.rs
+++ b/examples/not-send.rs
@@ -16,16 +16,21 @@ pub struct NotSend {
}
#[app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ use super::NotSend;
+
+ #[resources]
struct Resources {
#[init(None)]
shared: Option<NotSend>,
}
#[init(spawn = [baz, quux])]
- fn init(c: init::Context) {
+ fn init(c: init::Context) -> init::LateResources {
c.spawn.baz().unwrap();
c.spawn.quux().unwrap();
+
+ init::LateResources {}
}
#[task(spawn = [bar])]
@@ -60,4 +65,4 @@ const APP: () = {
fn SSI0();
fn QEI0();
}
-};
+}
diff --git a/examples/not-sync.rs b/examples/not-sync.rs
index a7eaac8e..75412e63 100644
--- a/examples/not-sync.rs
+++ b/examples/not-sync.rs
@@ -15,15 +15,21 @@ pub struct NotSync {
}
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ use super::NotSync;
+ use core::marker::PhantomData;
+
+ #[resources]
struct Resources {
#[init(NotSync { _0: PhantomData })]
shared: NotSync,
}
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
debug::exit(debug::EXIT_SUCCESS);
+
+ init::LateResources {}
}
#[task(resources = [&shared])]
@@ -42,4 +48,4 @@ const APP: () = {
extern "C" {
fn SSI0();
}
-};
+}
diff --git a/examples/only-shared-access.rs b/examples/only-shared-access.rs
index c022b037..91d0b7ad 100644
--- a/examples/only-shared-access.rs
+++ b/examples/only-shared-access.rs
@@ -10,7 +10,8 @@ use lm3s6965::Interrupt;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ #[resources]
struct Resources {
key: u32,
}
@@ -35,4 +36,4 @@ const APP: () = {
fn uart1(cx: uart1::Context) {
hprintln!("UART1(key = {:#x})", cx.resources.key).unwrap();
}
-};
+}
diff --git a/examples/periodic.rs b/examples/periodic.rs
index 405346e3..d3aedd32 100644
--- a/examples/periodic.rs
+++ b/examples/periodic.rs
@@ -13,12 +13,15 @@ const PERIOD: u32 = 8_000_000;
// NOTE: does NOT work on QEMU!
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
-const APP: () = {
+mod app {
+
#[init(schedule = [foo])]
- fn init(cx: init::Context) {
+ fn init(cx: init::Context) -> init::LateResources {
// omitted: initialization of `CYCCNT`
cx.schedule.foo(cx.start + PERIOD.cycles()).unwrap();
+
+ init::LateResources {}
}
#[task(schedule = [foo])]
@@ -35,4 +38,4 @@ const APP: () = {
extern "C" {
fn SSI0();
}
-};
+}
diff --git a/examples/peripherals-taken.rs b/examples/peripherals-taken.rs
index cd4ba0f0..09f92427 100644
--- a/examples/peripherals-taken.rs
+++ b/examples/peripherals-taken.rs
@@ -7,10 +7,12 @@ use cortex_m_semihosting::debug;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn main(_: main::Context) {
+ fn init(_: init::Context) -> init::LateResources {
assert!(cortex_m::Peripherals::take().is_none());
debug::exit(debug::EXIT_SUCCESS);
+
+ init::LateResources {}
}
-};
+}
diff --git a/examples/pool.rs b/examples/pool.rs
index 824d5bd8..cdbabca7 100644
--- a/examples/pool.rs
+++ b/examples/pool.rs
@@ -18,15 +18,22 @@ use rtic::app;
pool!(P: [u8; 128]);
#[app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ use crate::Box;
+
+ // Import the memory pool into scope
+ use super::P;
+
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
static mut MEMORY: [u8; 512] = [0; 512];
// Increase the capacity of the memory pool by ~4
P::grow(MEMORY);
rtic::pend(Interrupt::I2C0);
+
+ init::LateResources {}
}
#[task(binds = I2C0, priority = 2, spawn = [foo, bar])]
@@ -66,4 +73,4 @@ const APP: () = {
fn SSI0();
fn QEI0();
}
-};
+}
diff --git a/examples/preempt.rs b/examples/preempt.rs
index 3cb11029..f6fc4b05 100644
--- a/examples/preempt.rs
+++ b/examples/preempt.rs
@@ -9,10 +9,12 @@ use panic_semihosting as _;
use rtic::app;
#[app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::GPIOA);
+
+ init::LateResources {}
}
#[task(binds = GPIOA, priority = 1)]
@@ -34,4 +36,4 @@ const APP: () = {
rtic::pend(Interrupt::GPIOB);
hprintln!(" GPIOC - end").unwrap();
}
-};
+}
diff --git a/examples/ramfunc.rs b/examples/ramfunc.rs
index 1f95d496..5ff167a3 100644
--- a/examples/ramfunc.rs
+++ b/examples/ramfunc.rs
@@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init(spawn = [bar])]
- fn init(c: init::Context) {
+ fn init(c: init::Context) -> init::LateResources {
c.spawn.bar().unwrap();
+
+ init::LateResources {}
}
#[inline(never)]
@@ -38,4 +40,4 @@ const APP: () = {
#[link_section = ".data.UART1"]
fn UART1();
}
-};
+}
diff --git a/examples/resource-user-struct.rs b/examples/resource-user-struct.rs
new file mode 100644
index 00000000..a5bd0ddf
--- /dev/null
+++ b/examples/resource-user-struct.rs
@@ -0,0 +1,63 @@
+//! examples/resource.rs
+
+#![deny(unsafe_code)]
+#![deny(warnings)]
+#![no_main]
+#![no_std]
+
+use cortex_m_semihosting::{debug, hprintln};
+use lm3s6965::Interrupt;
+use panic_semihosting as _;
+
+#[rtic::app(device = lm3s6965)]
+mod app {
+ #[resources]
+ struct Resources {
+ // A resource
+ #[init(0)]
+ shared: u32,
+ }
+
+ // Should not collide with the struct above
+ #[allow(dead_code)]
+ struct Resources2 {
+ // A resource
+ shared: u32,
+ }
+
+ #[init]
+ fn init(_: init::Context) -> init::LateResources {
+ rtic::pend(Interrupt::UART0);
+ rtic::pend(Interrupt::UART1);
+
+ init::LateResources {}
+ }
+
+ // `shared` cannot be accessed from this context
+ #[idle]
+ fn idle(_cx: idle::Context) -> ! {
+ debug::exit(debug::EXIT_SUCCESS);
+
+ // error: no `resources` field in `idle::Context`
+ // _cx.resources.shared += 1;
+
+ loop {}
+ }
+
+ // `shared` can be accessed from this context
+ #[task(binds = UART0, resources = [shared])]
+ fn uart0(cx: uart0::Context) {
+ let shared: &mut u32 = cx.resources.shared;
+ *shared += 1;
+
+ hprintln!("UART0: shared = {}", shared).unwrap();
+ }
+
+ // `shared` can be accessed from this context
+ #[task(binds = UART1, resources = [shared])]
+ fn uart1(cx: uart1::Context) {
+ *cx.resources.shared += 1;
+
+ hprintln!("UART1: shared = {}", cx.resources.shared).unwrap();
+ }
+}
diff --git a/examples/resource.rs b/examples/resource.rs
index ded97f8e..273af26a 100644
--- a/examples/resource.rs
+++ b/examples/resource.rs
@@ -10,7 +10,8 @@ use lm3s6965::Interrupt;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ #[resources]
struct Resources {
// A resource
#[init(0)]
@@ -18,9 +19,11 @@ const APP: () = {
}
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
rtic::pend(Interrupt::UART0);
rtic::pend(Interrupt::UART1);
+
+ init::LateResources {}
}
// `shared` cannot be accessed from this context
@@ -31,7 +34,9 @@ const APP: () = {
// error: no `resources` field in `idle::Context`
// _cx.resources.shared += 1;
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
// `shared` can be accessed from this context
@@ -50,4 +55,4 @@ const APP: () = {
hprintln!("UART1: shared = {}", cx.resources.shared).unwrap();
}
-};
+}
diff --git a/examples/schedule.rs b/examples/schedule.rs
index 70a7a5e3..7e6adc1a 100644
--- a/examples/schedule.rs
+++ b/examples/schedule.rs
@@ -12,9 +12,9 @@ use rtic::cyccnt::{Instant, U32Ext as _};
// NOTE: does NOT work on QEMU!
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
-const APP: () = {
+mod app {
#[init(schedule = [foo, bar])]
- fn init(mut cx: init::Context) {
+ fn init(mut cx: init::Context) -> init::LateResources {
// Initialize (enable) the monotonic timer (CYCCNT)
cx.core.DCB.enable_trace();
// required on Cortex-M7 devices that software lock the DWT (e.g. STM32F7)
@@ -32,6 +32,8 @@ const APP: () = {
// Schedule `bar` to run 4e6 cycles in the future
cx.schedule.bar(now + 4_000_000.cycles()).unwrap();
+
+ init::LateResources {}
}
#[task]
@@ -50,4 +52,4 @@ const APP: () = {
extern "C" {
fn SSI0();
}
-};
+}
diff --git a/examples/shared-with-init.rs b/examples/shared-with-init.rs
index bd55f7ef..85c72761 100644
--- a/examples/shared-with-init.rs
+++ b/examples/shared-with-init.rs
@@ -13,19 +13,24 @@ use rtic::app;
pub struct MustBeSend;
#[app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ use super::MustBeSend;
+
+ #[resources]
struct Resources {
#[init(None)]
shared: Option<MustBeSend>,
}
#[init(resources = [shared])]
- fn init(c: init::Context) {
+ fn init(c: init::Context) -> init::LateResources {
// this `message` will be sent to task `UART0`
let message = MustBeSend;
*c.resources.shared = Some(message);
rtic::pend(Interrupt::UART0);
+
+ init::LateResources {}
}
#[task(binds = UART0, resources = [shared])]
@@ -37,4 +42,4 @@ const APP: () = {
debug::exit(debug::EXIT_SUCCESS);
}
}
-};
+}
diff --git a/examples/smallest.rs b/examples/smallest.rs
index ec3fa970..b8cbf87e 100644
--- a/examples/smallest.rs
+++ b/examples/smallest.rs
@@ -7,4 +7,4 @@ use panic_semihosting as _; // panic handler
use rtic::app;
#[app(device = lm3s6965)]
-const APP: () = {};
+mod app {}
diff --git a/examples/t-binds.rs b/examples/t-binds.rs
index 588ac46f..3ca4c66e 100644
--- a/examples/t-binds.rs
+++ b/examples/t-binds.rs
@@ -8,9 +8,11 @@
use panic_halt as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn init(_: init::Context) {}
+ fn init(_: init::Context) -> init::LateResources {
+ init::LateResources {}
+ }
// Cortex-M exception
#[task(binds = SVCall)]
@@ -23,7 +25,7 @@ const APP: () = {
fn bar(c: bar::Context) {
bar_trampoline(c)
}
-};
+}
#[allow(dead_code)]
fn foo_trampoline(_: foo::Context) {}
diff --git a/examples/t-cfg-resources.rs b/examples/t-cfg-resources.rs
index eb00fe59..61eb4c7b 100644
--- a/examples/t-cfg-resources.rs
+++ b/examples/t-cfg-resources.rs
@@ -6,19 +6,17 @@
use panic_halt as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ #[resources]
struct Resources {
// A resource
#[init(0)]
shared: u32,
-
// A conditionally compiled resource behind feature_x
#[cfg(feature = "feature_x")]
x: u32,
-
- dummy: (),
+ dummy: (), // dummy such that we have at least one late resource
}
-
#[init]
fn init(_: init::Context) -> init::LateResources {
init::LateResources {
@@ -31,6 +29,8 @@ const APP: () = {
#[idle]
fn idle(_cx: idle::Context) -> ! {
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
-};
+}
diff --git a/examples/t-cfg.rs b/examples/t-cfg.rs
index 52e6d1c9..3da20d4e 100644
--- a/examples/t-cfg.rs
+++ b/examples/t-cfg.rs
@@ -6,7 +6,8 @@
use panic_halt as _;
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
-const APP: () = {
+mod app {
+ #[resources]
struct Resources {
#[cfg(never)]
#[init(0)]
@@ -14,9 +15,11 @@ const APP: () = {
}
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
#[cfg(never)]
static mut BAR: u32 = 0;
+
+ init::LateResources {}
}
#[idle]
@@ -24,7 +27,9 @@ const APP: () = {
#[cfg(never)]
static mut BAR: u32 = 0;
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
#[task(resources = [foo], schedule = [quux], spawn = [quux])]
@@ -50,4 +55,4 @@ const APP: () = {
fn SSI0();
fn QEI0();
}
-};
+}
diff --git a/examples/t-htask-main.rs b/examples/t-htask-main.rs
index c4bebf94..1e38e317 100644
--- a/examples/t-htask-main.rs
+++ b/examples/t-htask-main.rs
@@ -7,14 +7,16 @@ use cortex_m_semihosting::debug;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn init(_: init::Context) {
- rtic::pend(lm3s6965::Interrupt::UART0)
+ fn init(_: init::Context) -> init::LateResources {
+ rtic::pend(lm3s6965::Interrupt::UART0);
+
+ init::LateResources {}
}
#[task(binds = UART0)]
- fn main(_: main::Context) {
+ fn taskmain(_: taskmain::Context) {
debug::exit(debug::EXIT_SUCCESS);
}
-};
+}
diff --git a/examples/t-idle-main.rs b/examples/t-idle-main.rs
index 94a33174..9078628e 100644
--- a/examples/t-idle-main.rs
+++ b/examples/t-idle-main.rs
@@ -7,13 +7,17 @@ use cortex_m_semihosting::debug;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn init(_: init::Context) {}
+ fn init(_: init::Context) -> init::LateResources {
+ init::LateResources {}
+ }
#[idle]
- fn main(_: main::Context) -> ! {
+ fn taskmain(_: taskmain::Context) -> ! {
debug::exit(debug::EXIT_SUCCESS);
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
-};
+}
diff --git a/examples/t-init-main.rs b/examples/t-init-main.rs
index 6a6cd991..7c23cc83 100644
--- a/examples/t-init-main.rs
+++ b/examples/t-init-main.rs
@@ -7,9 +7,11 @@ use cortex_m_semihosting::debug;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn main(_: main::Context) {
+ fn init(_: init::Context) -> init::LateResources {
debug::exit(debug::EXIT_SUCCESS);
+
+ init::LateResources {}
}
-};
+}
diff --git a/examples/t-late-not-send.rs b/examples/t-late-not-send.rs
index c464e73b..345d9aef 100644
--- a/examples/t-late-not-send.rs
+++ b/examples/t-late-not-send.rs
@@ -12,7 +12,10 @@ pub struct NotSend {
}
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ use super::NotSend;
+
+ #[resources]
struct Resources {
x: NotSend,
#[init(None)]
@@ -31,6 +34,8 @@ const APP: () = {
#[idle(resources = [x, y])]
fn idle(_: idle::Context) -> ! {
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
-};
+}
diff --git a/examples/t-resource.rs b/examples/t-resource.rs
index 53665dc9..91950d3e 100644
--- a/examples/t-resource.rs
+++ b/examples/t-resource.rs
@@ -8,7 +8,8 @@
use panic_halt as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ #[resources]
struct Resources {
#[init(0)]
o1: u32, // init
@@ -31,7 +32,7 @@ const APP: () = {
}
#[init(resources = [o1, o4, o5, o6, s3])]
- fn init(c: init::Context) {
+ fn init(c: init::Context) -> init::LateResources {
// owned by `init` == `&'static mut`
let _: &'static mut u32 = c.resources.o1;
@@ -42,6 +43,8 @@ const APP: () = {
let _: &mut u32 = c.resources.o4;
let _: &mut u32 = c.resources.o5;
let _: &mut u32 = c.resources.s3;
+
+ init::LateResources {}
}
#[idle(resources = [o2, &o4, s1, &s3])]
@@ -58,7 +61,9 @@ const APP: () = {
// `&` if read-only
let _: &u32 = c.resources.s3;
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
#[task(binds = UART0, resources = [o3, s1, s2, &s3])]
@@ -84,4 +89,4 @@ const APP: () = {
// no `Mutex` proxy when co-owned by cooperative (same priority) tasks
let _: &mut u32 = c.resources.s2;
}
-};
+}
diff --git a/examples/t-schedule.rs b/examples/t-schedule.rs
index 4a231822..d5a6d3ff 100644
--- a/examples/t-schedule.rs
+++ b/examples/t-schedule.rs
@@ -9,12 +9,14 @@ use panic_halt as _;
use rtic::cyccnt::{Instant, U32Ext as _};
#[rtic::app(device = lm3s6965, monotonic = rtic::cyccnt::CYCCNT)]
-const APP: () = {
+mod app {
#[init(schedule = [foo, bar, baz])]
- fn init(c: init::Context) {
+ fn init(c: init::Context) -> init::LateResources {
let _: Result<(), ()> = c.schedule.foo(c.start + 10.cycles());
let _: Result<(), u32> = c.schedule.bar(c.start + 20.cycles(), 0);
let _: Result<(), (u32, u32)> = c.schedule.baz(c.start + 30.cycles(), 0, 1);
+
+ init::LateResources {}
}
#[idle(schedule = [foo, bar, baz])]
@@ -23,7 +25,9 @@ const APP: () = {
let _: Result<(), u32> = c.schedule.bar(Instant::now() + 50.cycles(), 0);
let _: Result<(), (u32, u32)> = c.schedule.baz(Instant::now() + 60.cycles(), 0, 1);
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
#[task(binds = SVCall, schedule = [foo, bar, baz])]
@@ -59,4 +63,4 @@ const APP: () = {
extern "C" {
fn SSI0();
}
-};
+}
diff --git a/examples/t-spawn.rs b/examples/t-spawn.rs
index 2d941b15..efb748bc 100644
--- a/examples/t-spawn.rs
+++ b/examples/t-spawn.rs
@@ -8,12 +8,14 @@
use panic_halt as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init(spawn = [foo, bar, baz])]
- fn init(c: init::Context) {
+ fn init(c: init::Context) -> init::LateResources {
let _: Result<(), ()> = c.spawn.foo();
let _: Result<(), u32> = c.spawn.bar(0);
let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
+
+ init::LateResources {}
}
#[idle(spawn = [foo, bar, baz])]
@@ -22,7 +24,9 @@ const APP: () = {
let _: Result<(), u32> = c.spawn.bar(0);
let _: Result<(), (u32, u32)> = c.spawn.baz(0, 1);
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
#[task(binds = SVCall, spawn = [foo, bar, baz])]
@@ -58,4 +62,4 @@ const APP: () = {
extern "C" {
fn SSI0();
}
-};
+}
diff --git a/examples/t-stask-main.rs b/examples/t-stask-main.rs
index f2709404..74335c18 100644
--- a/examples/t-stask-main.rs
+++ b/examples/t-stask-main.rs
@@ -7,14 +7,16 @@ use cortex_m_semihosting::debug;
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
- #[init(spawn = [main])]
- fn init(cx: init::Context) {
- cx.spawn.main().ok();
+mod app {
+ #[init(spawn = [taskmain])]
+ fn init(cx: init::Context) -> init::LateResources {
+ cx.spawn.taskmain().ok();
+
+ init::LateResources {}
}
#[task]
- fn main(_: main::Context) {
+ fn taskmain(_: taskmain::Context) {
debug::exit(debug::EXIT_SUCCESS);
}
@@ -24,4 +26,4 @@ const APP: () = {
extern "C" {
fn SSI0();
}
-};
+}
diff --git a/examples/task.rs b/examples/task.rs
index 12c4ac83..80a9c431 100644
--- a/examples/task.rs
+++ b/examples/task.rs
@@ -9,10 +9,12 @@ use cortex_m_semihosting::{debug, hprintln};
use panic_semihosting as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init(spawn = [foo])]
- fn init(c: init::Context) {
+ fn init(c: init::Context) -> init::LateResources {
c.spawn.foo().unwrap();
+
+ init::LateResources {}
}
#[task(spawn = [bar, baz])]
@@ -52,4 +54,4 @@ const APP: () = {
fn SSI0();
fn QEI0();
}
-};
+}
diff --git a/examples/types.rs b/examples/types.rs
index e14ab0c8..251d004c 100644
--- a/examples/types.rs
+++ b/examples/types.rs
@@ -10,14 +10,15 @@ use panic_semihosting as _;
use rtic::cyccnt;
#[rtic::app(device = lm3s6965, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
-const APP: () = {
+mod app {
+ #[resources]
struct Resources {
#[init(0)]
shared: u32,
}
#[init(schedule = [foo], spawn = [foo])]
- fn init(cx: init::Context) {
+ fn init(cx: init::Context) -> init::LateResources {
let _: cyccnt::Instant = cx.start;
let _: rtic::Peripherals = cx.core;
let _: lm3s6965::Peripherals = cx.device;
@@ -25,6 +26,8 @@ const APP: () = {
let _: init::Spawn = cx.spawn;
debug::exit(debug::EXIT_SUCCESS);
+
+ init::LateResources {}
}
#[idle(schedule = [foo], spawn = [foo])]
@@ -32,7 +35,9 @@ const APP: () = {
let _: idle::Schedule = cx.schedule;
let _: idle::Spawn = cx.spawn;
- loop {}
+ loop {
+ cortex_m::asm::nop();
+ }
}
#[task(binds = UART0, resources = [shared], schedule = [foo], spawn = [foo])]
@@ -58,4 +63,4 @@ const APP: () = {
extern "C" {
fn SSI0();
}
-};
+}
diff --git a/heterogeneous/Cargo.toml b/heterogeneous/Cargo.toml
deleted file mode 100644
index 54808a2f..00000000
--- a/heterogeneous/Cargo.toml
+++ /dev/null
@@ -1,18 +0,0 @@
-[package]
-authors = ["Jorge Aparicio <jorge@japaric.io>"]
-edition = "2018"
-name = "heterogeneous"
-# this crate is only used for testing
-publish = false
-version = "0.0.0-alpha.0"
-
-[dependencies]
-bare-metal = "0.2.4"
-
-[dependencies.cortex-m-rtic]
-path = ".."
-features = ["heterogeneous"]
-
-[dev-dependencies]
-panic-halt = "0.2.0"
-microamp = "0.1.0-alpha.1"
diff --git a/heterogeneous/README.md b/heterogeneous/README.md
deleted file mode 100644
index 8e49ff8b..00000000
--- a/heterogeneous/README.md
+++ /dev/null
@@ -1 +0,0 @@
-This directory contains *heterogeneous* multi-core compile pass tests.
diff --git a/heterogeneous/examples/smallest.rs b/heterogeneous/examples/smallest.rs
deleted file mode 100644
index 2074e7dc..00000000
--- a/heterogeneous/examples/smallest.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#![no_main]
-#![no_std]
-
-use panic_halt as _;
-
-#[rtic::app(cores = 2, device = heterogeneous)]
-const APP: () = {};
diff --git a/heterogeneous/examples/x-init-2.rs b/heterogeneous/examples/x-init-2.rs
deleted file mode 100644
index e6ec7fca..00000000
--- a/heterogeneous/examples/x-init-2.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-//! [compile-pass] Cross initialization of late resources
-
-#![deny(unsafe_code)]
-#![deny(warnings)]
-#![no_main]
-#![no_std]
-
-use panic_halt as _;
-
-#[rtic::app(cores = 2, device = heterogeneous)]
-const APP: () = {
- struct Resources {
- // owned by core #1 but initialized by core #0
- x: u32,
-
- // owned by core #0 but initialized by core #1
- y: u32,
- }
-
- #[init(core = 0, late = [x])]
- fn a(_: a::Context) -> a::LateResources {
- a::LateResources { x: 0 }
- }
-
- #[idle(core = 0, resources = [y])]
- fn b(_: b::Context) -> ! {
- loop {}
- }
-
- #[init(core = 1)]
- fn c(_: c::Context) -> c::LateResources {
- c::LateResources { y: 0 }
- }
-
- #[idle(core = 1, resources = [x])]
- fn d(_: d::Context) -> ! {
- loop {}
- }
-};
diff --git a/heterogeneous/examples/x-init.rs b/heterogeneous/examples/x-init.rs
deleted file mode 100644
index 20601b1a..00000000
--- a/heterogeneous/examples/x-init.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-//! [compile-pass] Split initialization of late resources
-
-#![deny(unsafe_code)]
-#![deny(warnings)]
-#![no_main]
-#![no_std]
-
-use panic_halt as _;
-
-#[rtic::app(cores = 2, device = heterogeneous)]
-const APP: () = {
- struct Resources {
- x: u32,
- y: u32,
- }
-
- #[init(core = 0, late = [x])]
- fn a(_: a::Context) -> a::LateResources {
- a::LateResources { x: 0 }
- }
-
- #[init(core = 1)]
- fn b(_: b::Context) -> b::LateResources {
- b::LateResources { y: 0 }
- }
-};
diff --git a/heterogeneous/examples/x-schedule.rs b/heterogeneous/examples/x-schedule.rs
deleted file mode 100644
index 98a5f741..00000000
--- a/heterogeneous/examples/x-schedule.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-#![no_main]
-#![no_std]
-
-use panic_halt as _;
-
-#[rtic::app(cores = 2, device = heterogeneous, monotonic = heterogeneous::MT)]
-const APP: () = {
- #[init(core = 0, spawn = [ping])]
- fn init(c: init::Context) {
- c.spawn.ping().ok();
- }
-
- #[task(core = 0, schedule = [ping])]
- fn pong(c: pong::Context) {
- c.schedule.ping(c.scheduled + 1_000_000).ok();
- }
-
- #[task(core = 1, schedule = [pong])]
- fn ping(c: ping::Context) {
- c.schedule.pong(c.scheduled + 1_000_000).ok();
- }
-
- extern "C" {
- #[core = 0]
- fn I0();
-
- #[core = 0]
- fn I1();
-
- #[core = 1]
- fn I0();
-
- #[core = 1]
- fn I1();
- }
-};
diff --git a/heterogeneous/examples/x-spawn.rs b/heterogeneous/examples/x-spawn.rs
deleted file mode 100644
index e2586210..00000000
--- a/heterogeneous/examples/x-spawn.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-#![no_main]
-#![no_std]
-
-use panic_halt as _;
-
-#[rtic::app(cores = 2, device = heterogeneous)]
-const APP: () = {
- #[init(core = 0, spawn = [foo])]
- fn init(c: init::Context) {
- c.spawn.foo().ok();
- }
-
- #[task(core = 1)]
- fn foo(_: foo::Context) {}
-
- extern "C" {
- #[core = 1]
- fn I0();
- }
-};
diff --git a/heterogeneous/src/lib.rs b/heterogeneous/src/lib.rs
deleted file mode 100644
index 1bda7c85..00000000
--- a/heterogeneous/src/lib.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-//! Fake multi-core PAC
-
-#![no_std]
-
-use core::{
- cmp::Ordering,
- ops::{Add, Sub},
-};
-
-use bare_metal::Nr;
-use rtic::{Fraction, Monotonic, MultiCore};
-
-// both cores have the exact same interrupts
-pub use Interrupt_0 as Interrupt_1;
-
-// Fake priority bits
-pub const NVIC_PRIO_BITS: u8 = 3;
-
-pub fn xpend(_core: u8, _interrupt: impl Nr) {}
-
-/// Fake monotonic timer
-pub struct MT;
-
-impl Monotonic for MT {
- type Instant = Instant;
-
- fn ratio() -> Fraction {
- Fraction {
- numerator: 1,
- denominator: 1,
- }
- }
-
- unsafe fn reset() {
- (0xE0001004 as *mut u32).write_volatile(0)
- }
-
- fn now() -> Instant {
- unsafe { Instant((0xE0001004 as *const u32).read_volatile() as i32) }
- }
-
- fn zero() -> Instant {
- Instant(0)
- }
-}
-
-impl MultiCore for MT {}
-
-#[derive(Clone, Copy, Eq, PartialEq)]
-pub struct Instant(i32);
-
-impl Add<u32> for Instant {
- type Output = Instant;
-
- fn add(self, rhs: u32) -> Self {
- Instant(self.0.wrapping_add(rhs as i32))
- }
-}
-
-impl Sub for Instant {
- type Output = u32;
-
- fn sub(self, rhs: Self) -> u32 {
- self.0.checked_sub(rhs.0).unwrap() as u32
- }
-}
-
-impl Ord for Instant {
- fn cmp(&self, rhs: &Self) -> Ordering {
- self.0.wrapping_sub(rhs.0).cmp(&0)
- }
-}
-
-impl PartialOrd for Instant {
- fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
- Some(self.cmp(rhs))
- }
-}
-
-// Fake interrupts
-#[allow(non_camel_case_types)]
-#[derive(Clone, Copy)]
-#[repr(u8)]
-pub enum Interrupt_0 {
- I0 = 0,
- I1 = 1,
- I2 = 2,
- I3 = 3,
- I4 = 4,
- I5 = 5,
- I6 = 6,
- I7 = 7,
-}
-
-unsafe impl Nr for Interrupt_0 {
- fn nr(&self) -> u8 {
- *self as u8
- }
-}
diff --git a/homogeneous/Cargo.toml b/homogeneous/Cargo.toml
deleted file mode 100644
index 111fe5df..00000000
--- a/homogeneous/Cargo.toml
+++ /dev/null
@@ -1,17 +0,0 @@
-[package]
-authors = ["Jorge Aparicio <jorge@japaric.io>"]
-edition = "2018"
-name = "homogeneous"
-# this crate is only used for testing
-publish = false
-version = "0.0.0-alpha.0"
-
-[dependencies]
-bare-metal = "0.2.4"
-
-[dependencies.cortex-m-rtic]
-path = ".."
-features = ["homogeneous"]
-
-[dev-dependencies]
-panic-halt = "0.2.0"
diff --git a/homogeneous/README.md b/homogeneous/README.md
deleted file mode 100644
index 17e9c6e1..00000000
--- a/homogeneous/README.md
+++ /dev/null
@@ -1 +0,0 @@
-This directory contains *homogeneous* multi-core compile pass tests.
diff --git a/homogeneous/examples/smallest.rs b/homogeneous/examples/smallest.rs
deleted file mode 100644
index 913e489f..00000000
--- a/homogeneous/examples/smallest.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#![no_main]
-#![no_std]
-
-use panic_halt as _;
-
-#[rtic::app(cores = 2, device = homogeneous)]
-const APP: () = {};
diff --git a/homogeneous/examples/x-init-2.rs b/homogeneous/examples/x-init-2.rs
deleted file mode 100644
index 11caacd4..00000000
--- a/homogeneous/examples/x-init-2.rs
+++ /dev/null
@@ -1,39 +0,0 @@
-//! [compile-pass] Cross initialization of late resources
-
-#![deny(unsafe_code)]
-#![deny(warnings)]
-#![no_main]
-#![no_std]
-
-use panic_halt as _;
-
-#[rtic::app(cores = 2, device = homogeneous)]
-const APP: () = {
- struct Resources {
- // owned by core #1 but initialized by core #0
- x: u32,
-
- // owned by core #0 but initialized by core #1
- y: u32,
- }
-
- #[init(core = 0, late = [x])]
- fn a(_: a::Context) -> a::LateResources {
- a::LateResources { x: 0 }
- }
-
- #[idle(core = 0, resources = [y])]
- fn b(_: b::Context) -> ! {
- loop {}
- }
-
- #[init(core = 1)]
- fn c(_: c::Context) -> c::LateResources {
- c::LateResources { y: 0 }
- }
-
- #[idle(core = 1, resources = [x])]
- fn d(_: d::Context) -> ! {
- loop {}
- }
-};
diff --git a/homogeneous/examples/x-init.rs b/homogeneous/examples/x-init.rs
deleted file mode 100644
index 0574279c..00000000
--- a/homogeneous/examples/x-init.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-//! [compile-pass] Split initialization of late resources
-
-#![deny(unsafe_code)]
-#![deny(warnings)]
-#![no_main]
-#![no_std]
-
-use panic_halt as _;
-
-#[rtic::app(cores = 2, device = homogeneous)]
-const APP: () = {
- struct Resources {
- x: u32,
- y: u32,
- }
-
- #[init(core = 0, late = [x])]
- fn a(_: a::Context) -> a::LateResources {
- a::LateResources { x: 0 }
- }
-
- #[init(core = 1)]
- fn b(_: b::Context) -> b::LateResources {
- b::LateResources { y: 0 }
- }
-};
diff --git a/homogeneous/examples/x-schedule.rs b/homogeneous/examples/x-schedule.rs
deleted file mode 100644
index 7c0b3840..00000000
--- a/homogeneous/examples/x-schedule.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-#![no_main]
-#![no_std]
-
-use panic_halt as _;
-
-#[rtic::app(cores = 2, device = homogeneous, monotonic = homogeneous::MT)]
-const APP: () = {
- #[init(core = 0, spawn = [ping])]
- fn init(c: init::Context) {
- c.spawn.ping().ok();
- }
-
- #[task(core = 0, schedule = [ping])]
- fn pong(c: pong::Context) {
- c.schedule.ping(c.scheduled + 1_000_000).ok();
- }
-
- #[task(core = 1, schedule = [pong])]
- fn ping(c: ping::Context) {
- c.schedule.pong(c.scheduled + 1_000_000).ok();
- }
-
- extern "C" {
- #[core = 0]
- fn I0();
-
- #[core = 0]
- fn I1();
-
- #[core = 1]
- fn I0();
-
- #[core = 1]
- fn I1();
- }
-};
diff --git a/homogeneous/examples/x-spawn.rs b/homogeneous/examples/x-spawn.rs
deleted file mode 100644
index 45bc9003..00000000
--- a/homogeneous/examples/x-spawn.rs
+++ /dev/null
@@ -1,20 +0,0 @@
-#![no_main]
-#![no_std]
-
-use panic_halt as _;
-
-#[rtic::app(cores = 2, device = homogeneous)]
-const APP: () = {
- #[init(core = 0, spawn = [foo])]
- fn init(c: init::Context) {
- c.spawn.foo().ok();
- }
-
- #[task(core = 1)]
- fn foo(_: foo::Context) {}
-
- extern "C" {
- #[core = 1]
- fn I0();
- }
-};
diff --git a/homogeneous/src/lib.rs b/homogeneous/src/lib.rs
deleted file mode 100644
index 1bda7c85..00000000
--- a/homogeneous/src/lib.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-//! Fake multi-core PAC
-
-#![no_std]
-
-use core::{
- cmp::Ordering,
- ops::{Add, Sub},
-};
-
-use bare_metal::Nr;
-use rtic::{Fraction, Monotonic, MultiCore};
-
-// both cores have the exact same interrupts
-pub use Interrupt_0 as Interrupt_1;
-
-// Fake priority bits
-pub const NVIC_PRIO_BITS: u8 = 3;
-
-pub fn xpend(_core: u8, _interrupt: impl Nr) {}
-
-/// Fake monotonic timer
-pub struct MT;
-
-impl Monotonic for MT {
- type Instant = Instant;
-
- fn ratio() -> Fraction {
- Fraction {
- numerator: 1,
- denominator: 1,
- }
- }
-
- unsafe fn reset() {
- (0xE0001004 as *mut u32).write_volatile(0)
- }
-
- fn now() -> Instant {
- unsafe { Instant((0xE0001004 as *const u32).read_volatile() as i32) }
- }
-
- fn zero() -> Instant {
- Instant(0)
- }
-}
-
-impl MultiCore for MT {}
-
-#[derive(Clone, Copy, Eq, PartialEq)]
-pub struct Instant(i32);
-
-impl Add<u32> for Instant {
- type Output = Instant;
-
- fn add(self, rhs: u32) -> Self {
- Instant(self.0.wrapping_add(rhs as i32))
- }
-}
-
-impl Sub for Instant {
- type Output = u32;
-
- fn sub(self, rhs: Self) -> u32 {
- self.0.checked_sub(rhs.0).unwrap() as u32
- }
-}
-
-impl Ord for Instant {
- fn cmp(&self, rhs: &Self) -> Ordering {
- self.0.wrapping_sub(rhs.0).cmp(&0)
- }
-}
-
-impl PartialOrd for Instant {
- fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
- Some(self.cmp(rhs))
- }
-}
-
-// Fake interrupts
-#[allow(non_camel_case_types)]
-#[derive(Clone, Copy)]
-#[repr(u8)]
-pub enum Interrupt_0 {
- I0 = 0,
- I1 = 1,
- I2 = 2,
- I3 = 3,
- I4 = 4,
- I5 = 5,
- I6 = 6,
- I7 = 7,
-}
-
-unsafe impl Nr for Interrupt_0 {
- fn nr(&self) -> u8 {
- *self as u8
- }
-}
diff --git a/macros/Cargo.toml b/macros/Cargo.toml
index 2a4e4c82..610890bb 100644
--- a/macros/Cargo.toml
+++ b/macros/Cargo.toml
@@ -12,7 +12,7 @@ license = "MIT OR Apache-2.0"
name = "cortex-m-rtic-macros"
readme = "../README.md"
repository = "https://github.com/rtic-rs/cortex-m-rtic"
-version = "0.5.0"
+version = "0.5.2"
[lib]
proc-macro = true
@@ -21,8 +21,5 @@ proc-macro = true
proc-macro2 = "1"
quote = "1"
syn = "1"
-rtic-syntax = "0.4.0"
+rtic-syntax = { git = "https://github.com/rtic-rs/rtic-syntax", branch = "master", version = "0.4.0" }
-[features]
-heterogeneous = []
-homogeneous = []
diff --git a/macros/src/analyze.rs b/macros/src/analyze.rs
index af6811fa..38018c8c 100644
--- a/macros/src/analyze.rs
+++ b/macros/src/analyze.rs
@@ -4,14 +4,14 @@ use std::collections::{BTreeMap, BTreeSet};
use rtic_syntax::{
analyze::{self, Priority},
ast::App,
- Core, P,
+ P,
};
use syn::Ident;
/// Extend the upstream `Analysis` struct with our field
pub struct Analysis {
parent: P<analyze::Analysis>,
- pub interrupts: BTreeMap<Core, BTreeMap<Priority, Ident>>,
+ pub interrupts: BTreeMap<Priority, Ident>,
}
impl ops::Deref for Analysis {
@@ -25,31 +25,20 @@ impl ops::Deref for Analysis {
// Assign an `extern` interrupt to each priority level
pub fn app(analysis: P<analyze::Analysis>, app: &App) -> P<Analysis> {
let mut interrupts = BTreeMap::new();
- for core in 0..app.args.cores {
- let priorities = app
- .software_tasks
- .values()
- .filter_map(|task| {
- if task.args.core == core {
- Some(task.args.priority)
- } else {
- None
- }
- })
- .chain(analysis.timer_queues.get(&core).map(|tq| tq.priority))
- .collect::<BTreeSet<_>>();
+ let priorities = app
+ .software_tasks
+ .values()
+ .filter_map(|task| Some(task.args.priority))
+ .chain(analysis.timer_queues.first().map(|tq| tq.priority))
+ .collect::<BTreeSet<_>>();
- if !priorities.is_empty() {
- interrupts.insert(
- core,
- priorities
- .iter()
- .cloned()
- .rev()
- .zip(app.extern_interrupts[&core].keys().cloned())
- .collect(),
- );
- }
+ if !priorities.is_empty() {
+ interrupts = priorities
+ .iter()
+ .cloned()
+ .rev()
+ .zip(app.extern_interrupts.keys().cloned())
+ .collect();
}
P::new(Analysis {
diff --git a/macros/src/check.rs b/macros/src/check.rs
index 71634446..0e57bb73 100644
--- a/macros/src/check.rs
+++ b/macros/src/check.rs
@@ -10,7 +10,7 @@ use syn::{parse, Path};
pub struct Extra<'a> {
pub device: &'a Path,
pub monotonic: Option<&'a Path>,
- pub peripherals: Option<u8>,
+ pub peripherals: bool,
}
impl<'a> Extra<'a> {
@@ -20,35 +20,14 @@ impl<'a> Extra<'a> {
}
pub fn app<'a>(app: &'a App, analysis: &Analysis) -> parse::Result<Extra<'a>> {
- if cfg!(feature = "homogeneous") {
- // this RTIC mode uses the same namespace for all cores so we need to check that the
- // identifiers used for each core `#[init]` and `#[idle]` functions don't collide
- let mut seen = HashSet::new();
-
- for name in app
- .inits
- .values()
- .map(|init| &init.name)
- .chain(app.idles.values().map(|idle| &idle.name))
- {
- if seen.contains(name) {
- return Err(parse::Error::new(
- name.span(),
- "this identifier is already being used by another core",
- ));
- } else {
- seen.insert(name);
- }
- }
- }
-
- // check that all exceptions are valid; only exceptions with configurable priorities are
+ // Check that all exceptions are valid; only exceptions with configurable priorities are
// accepted
for (name, task) in &app.hardware_tasks {
let name_s = task.args.binds.to_string();
match &*name_s {
"SysTick" => {
- if analysis.timer_queues.get(&task.args.core).is_some() {
+ // If the timer queue is used, then SysTick is unavailable
+ if !analysis.timer_queues.is_empty() {
return Err(parse::Error::new(
name.span(),
"this exception can't be used because it's being used by the runtime",
@@ -69,13 +48,9 @@ pub fn app<'a>(app: &'a App, analysis: &Analysis) -> parse::Result<Extra<'a>> {
}
}
- // check that external (device-specific) interrupts are not named after known (Cortex-M)
+ // Check that external (device-specific) interrupts are not named after known (Cortex-M)
// exceptions
- for name in app
- .extern_interrupts
- .iter()
- .flat_map(|(_, interrupts)| interrupts.keys())
- {
+ for name in app.extern_interrupts.keys() {
let name_s = name.to_string();
match &*name_s {
@@ -91,52 +66,38 @@ pub fn app<'a>(app: &'a App, analysis: &Analysis) -> parse::Result<Extra<'a>> {
}
}
- // check that there are enough external interrupts to dispatch the software tasks and the timer
+ // Check that there are enough external interrupts to dispatch the software tasks and the timer
// queue handler
- for core in 0..app.args.cores {
- let mut first = None;
- let priorities = app
- .software_tasks
- .iter()
- .filter_map(|(name, task)| {
- if task.args.core == core {
- first = Some(name);
- Some(task.args.priority)
- } else {
- None
- }
- })
- .chain(analysis.timer_queues.get(&core).map(|tq| tq.priority))
- .collect::<HashSet<_>>();
-
- let need = priorities.len();
- let given = app
- .extern_interrupts
- .get(&core)
- .map(|ei| ei.len())
- .unwrap_or(0);
- if need > given {
- let s = if app.args.cores == 1 {
- format!(
- "not enough `extern` interrupts to dispatch \
- all software tasks (need: {}; given: {})",
- need, given
- )
- } else {
- format!(
- "not enough `extern` interrupts to dispatch \
- all software tasks on this core (need: {}; given: {})",
- need, given
- )
- };
-
- return Err(parse::Error::new(first.unwrap().span(), &s));
- }
+ let mut first = None;
+ let priorities = app
+ .software_tasks
+ .iter()
+ .filter_map(|(name, task)| {
+ first = Some(name);
+ Some(task.args.priority)
+ })
+ .chain(analysis.timer_queues.first().map(|tq| tq.priority))
+ .collect::<HashSet<_>>();
+
+ let need = priorities.len();
+ let given = app.extern_interrupts.len();
+ if need > given {
+ let s = {
+ format!(
+ "not enough `extern` interrupts to dispatch \
+ all software tasks (need: {}; given: {})",
+ need, given
+ )
+ };
+
+ // If not enough tasks and first still is None, may cause
+ // "custom attribute panicked" due to unwrap on None
+ return Err(parse::Error::new(first.unwrap().span(), &s));
}
let mut device = None;
let mut monotonic = None;
- let mut peripherals = None;
+ let mut peripherals = false;
for (k, v) in &app.args.custom {
let ks = k.to_string();
@@ -165,34 +126,11 @@ pub fn app<'a>(app: &'a App, analysis: &Analysis) -> parse::Result<Extra<'a>> {
},
"peripherals" => match v {
- CustomArg::Bool(x) if app.args.cores == 1 => {
- peripherals = if *x { Some(0) } else { None }
- }
-
- CustomArg::UInt(s) if app.args.cores != 1 => {
- let x = s.parse::<u8>().ok();
- peripherals = if x.is_some() && x.unwrap() < app.args.cores {
- Some(x.unwrap())
- } else {
- return Err(parse::Error::new(
- k.span(),
- &format!(
- "unexpected argument value; \
- this should be an integer in the range 0..={}",
- app.args.cores
- ),
- ));
- }
- }
-
+ CustomArg::Bool(x) => peripherals = if *x { true } else { false },
_ => {
return Err(parse::Error::new(
k.span(),
- if app.args.cores == 1 {
- "unexpected argument value; this should be a boolean"
- } else {
- "unexpected argument value; this should be an integer"
- },
+ "unexpected argument value; this should be a boolean",
));
}
},
@@ -203,7 +141,7 @@ pub fn app<'a>(app: &'a App, analysis: &Analysis) -> parse::Result<Extra<'a>> {
}
}
- if !analysis.timer_queues.is_empty() && monotonic.is_none() {
+ if !&analysis.timer_queues.is_empty() && monotonic.is_none() {
return Err(parse::Error::new(
Span::call_site(),
"a `monotonic` timer must be specified to use the `schedule` API",
diff --git a/macros/src/codegen.rs b/macros/src/codegen.rs
index 2433684c..f230d395 100644
--- a/macros/src/codegen.rs
+++ b/macros/src/codegen.rs
@@ -25,99 +25,105 @@ mod util;
// TODO document the syntax here or in `rtic-syntax`
pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
- let mut const_app = vec![];
+ let mut mod_app = vec![];
+ let mut mod_app_imports = vec![];
let mut mains = vec![];
let mut root = vec![];
let mut user = vec![];
+ let mut imports = vec![];
- // generate a `main` function for each core
- for core in 0..app.args.cores {
- let assertion_stmts = assertions::codegen(core, analysis, extra);
+ // Generate the `main` function
+ let assertion_stmts = assertions::codegen(analysis);
- let (const_app_pre_init, pre_init_stmts) = pre_init::codegen(core, &app, analysis, extra);
+ let pre_init_stmts = pre_init::codegen(&app, analysis, extra);
- let (const_app_init, root_init, user_init, call_init) =
- init::codegen(core, app, analysis, extra);
+ let (mod_app_init, root_init, user_init, user_init_imports, call_init) =
+ init::codegen(app, analysis, extra);
- let (const_app_post_init, post_init_stmts) =
- post_init::codegen(core, &app, analysis, extra);
+ let post_init_stmts = post_init::codegen(&app, analysis);
- let (const_app_idle, root_idle, user_idle, call_idle) =
- idle::codegen(core, app, analysis, extra);
+ let (mod_app_idle, root_idle, user_idle, user_idle_imports, call_idle) =
+ idle::codegen(app, analysis, extra);
- user.push(quote!(
- #user_init
-
- #user_idle
- ));
+ if user_init.is_some() {
+ mod_app_imports.push(quote!(
+ use super::init;
+ ))
+ }
+ if user_idle.is_some() {
+ mod_app_imports.push(quote!(
+ use super::idle;
+ ))
+ }
- root.push(quote!(
- #(#root_init)*
+ user.push(quote!(
+ #user_init
- #(#root_idle)*
- ));
+ #user_idle
+ ));
- const_app.push(quote!(
- #(#const_app_pre_init)*
+ imports.push(quote!(
+ #(#user_init_imports)*
+ #(#user_idle_imports)*
+ ));
- #const_app_init
+ root.push(quote!(
+ #(#root_init)*
- #(#const_app_post_init)*
+ #(#root_idle)*
+ ));
- #const_app_idle
- ));
+ mod_app.push(quote!(
+ #mod_app_init
- let cfg_core = util::cfg_core(core, app.args.cores);
- let main = util::suffixed("main", core);
- let section = util::link_section("text", core);
- mains.push(quote!(
- #[no_mangle]
- #section
- #cfg_core
- unsafe extern "C" fn #main() -> ! {
- let _TODO: () = ();
+ #mod_app_idle
+ ));
- #(#assertion_stmts)*
+ let main = util::suffixed("main");
+ mains.push(quote!(
+ #[no_mangle]
+ unsafe extern "C" fn #main() -> ! {
+ let _TODO: () = ();
- #(#pre_init_stmts)*
+ #(#assertion_stmts)*
- #call_init
+ #(#pre_init_stmts)*
- #(#post_init_stmts)*
+ #call_init
- #call_idle
- }
- ));
- }
+ #(#post_init_stmts)*
- let (const_app_resources, mod_resources) = resources::codegen(app, analysis, extra);
+ #call_idle
+ }
+ ));
- let (const_app_hardware_tasks, root_hardware_tasks, user_hardware_tasks) =
- hardware_tasks::codegen(app, analysis, extra);
+ let (mod_app_resources, mod_resources, mod_resources_imports) =
+ resources::codegen(app, analysis, extra);
- let (const_app_software_tasks, root_software_tasks, user_software_tasks) =
- software_tasks::codegen(app, analysis, extra);
+ let (
+ mod_app_hardware_tasks,
+ root_hardware_tasks,
+ user_hardware_tasks,
+ user_hardware_tasks_imports,
+ ) = hardware_tasks::codegen(app, analysis, extra);
- let const_app_dispatchers = dispatchers::codegen(app, analysis, extra);
+ let (
+ mod_app_software_tasks,
+ root_software_tasks,
+ user_software_tasks,
+ user_software_tasks_imports,
+ ) = software_tasks::codegen(app, analysis, extra);
- let const_app_spawn = spawn::codegen(app, analysis, extra);
+ let mod_app_dispatchers = dispatchers::codegen(app, analysis, extra);
- let const_app_timer_queue = timer_queue::codegen(app, analysis, extra);
+ let mod_app_spawn = spawn::codegen(app, analysis, extra);
- let const_app_schedule = schedule::codegen(app, extra);
+ let mod_app_timer_queue = timer_queue::codegen(app, analysis, extra);
- let cores = app.args.cores.to_string();
- let cfg_core = quote!(#[cfg(core = #cores)]);
- let msg = format!(
- "specified {} core{} but tried to compile for more than {0} core{1}",
- app.args.cores,
- if app.args.cores > 1 { "s" } else { "" }
- );
- let check_excess_cores = quote!(
- #cfg_core
- compile_error!(#msg);
- );
+ let mod_app_schedule = schedule::codegen(app, extra);
+ let user_imports = app.user_imports.clone();
+ let user_code = app.user_code.clone();
let name = &app.name;
let device = extra.device;
quote!(
@@ -136,30 +142,41 @@ pub fn app(app: &App, analysis: &Analysis, extra: &Extra) -> TokenStream2 {
#(#root_software_tasks)*
/// Implementation details
- // the user can't access the items within this `const` item
- const #name: () = {
+ mod #name {
/// Always include the device crate which contains the vector table
use #device as _;
+ #(#imports)*
+ #(#user_imports)*
+
+ /// User code from within the module
+ #(#user_code)*
+ /// User code end
+
+
+ #(#user_hardware_tasks_imports)*
+
+ #(#user_software_tasks_imports)*
- #check_excess_cores
+ #(#mod_resources_imports)*
- #(#const_app)*
+ /// app module
+ #(#mod_app)*
- #(#const_app_resources)*
+ #(#mod_app_resources)*
- #(#const_app_hardware_tasks)*
+ #(#mod_app_hardware_tasks)*
- #(#const_app_software_tasks)*
+ #(#mod_app_software_tasks)*
- #(#const_app_dispatchers)*
+ #(#mod_app_dispatchers)*
- #(#const_app_spawn)*
+ #(#mod_app_spawn)*
- #(#const_app_timer_queue)*
+ #(#mod_app_timer_queue)*
- #(#const_app_schedule)*
+ #(#mod_app_schedule)*
#(#mains)*
- };
+ }
)
}
diff --git a/macros/src/codegen/assertions.rs b/macros/src/codegen/assertions.rs
index 51bbdbff..4d9aae47 100644
--- a/macros/src/codegen/assertions.rs
+++ b/macros/src/codegen/assertions.rs
@@ -1,32 +1,18 @@
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
-use crate::{analyze::Analysis, check::Extra};
+use crate::analyze::Analysis;
/// Generates compile-time assertions that check that types implement the `Send` / `Sync` traits
-pub fn codegen(core: u8, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
+pub fn codegen(analysis: &Analysis) -> Vec<TokenStream2> {
let mut stmts = vec![];
- // we don't generate *all* assertions on all cores because the user could conditionally import a
- // type only on some core (e.g. `#[cfg(core = "0")] use some::Type;`)
-
- if let Some(types) = analysis.send_types.get(&core) {
- for ty in types {
- stmts.push(quote!(rtic::export::assert_send::<#ty>();));
- }
- }
-
- if let Some(types) = analysis.sync_types.get(&core) {
- for ty in types {
- stmts.push(quote!(rtic::export::assert_sync::<#ty>();));
- }
+ for ty in &analysis.send_types {
+ stmts.push(quote!(rtic::export::assert_send::<#ty>();));
}
- // if the `schedule` API is used in more than one core then we need to check that the
- // `monotonic` timer can be used in multi-core context
- if analysis.timer_queues.len() > 1 && analysis.timer_queues.contains_key(&core) {
- let monotonic = extra.monotonic();
- stmts.push(quote!(rtic::export::assert_multicore::<#monotonic>();));
+ for ty in &analysis.sync_types {
+ stmts.push(quote!(rtic::export::assert_sync::<#ty>();));
}
stmts
diff --git a/macros/src/codegen/dispatchers.rs b/macros/src/codegen/dispatchers.rs
index 60b8626e..300aa996 100644
--- a/macros/src/codegen/dispatchers.rs
+++ b/macros/src/codegen/dispatchers.rs
@@ -8,181 +8,147 @@ use crate::{analyze::Analysis, check::Extra, codegen::util};
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
let mut items = vec![];
- for (&receiver, dispatchers) in &analysis.channels {
- let interrupts = &analysis.interrupts[&receiver];
+ let interrupts = &analysis.interrupts;
+
+ for (&level, channel) in &analysis.channels {
+ let mut stmts = vec![];
+
+ let variants = channel
+ .tasks
+ .iter()
+ .map(|name| {
+ let cfgs = &app.software_tasks[name].cfgs;
+
+ quote!(
+ #(#cfgs)*
+ #name
+ )
+ })
+ .collect::<Vec<_>>();
+
+ let doc = format!(
+ "Software tasks to be dispatched at priority level {}",
+ level,
+ );
+ let t = util::spawn_t_ident(level);
+ items.push(quote!(
+ #[allow(non_camel_case_types)]
+ #[derive(Clone, Copy)]
+ #[doc = #doc]
+ enum #t {
+ #(#variants,)*
+ }
+ ));
+
+ let n = util::capacity_typenum(channel.capacity, true);
+ let rq = util::rq_ident(level);
+ let (rq_ty, rq_expr) = {
+ (
+ quote!(rtic::export::SCRQ<#t, #n>),
+ quote!(rtic::export::Queue(unsafe {
+ rtic::export::iQueue::u8_sc()
+ })),
+ )
+ };
+
+ let doc = format!(
+ "Queue of tasks ready to be dispatched at priority level {}",
+ level
+ );
+ items.push(quote!(
+ #[doc = #doc]
+ static mut #rq: #rq_ty = #rq_expr;
+ ));
+
+ if let Some(ceiling) = channel.ceiling {
+ items.push(quote!(
+ struct #rq<'a> {
+ priority: &'a rtic::export::Priority,
+ }
+ ));
- for (&level, channels) in dispatchers {
- let mut stmts = vec![];
+ items.push(util::impl_mutex(
+ extra,
+ &[],
+ false,
+ &rq,
+ rq_ty,
+ ceiling,
+ quote!(&mut #rq),
+ ));
+ }
- for (&sender, channel) in channels {
- let cfg_sender = util::cfg_core(sender, app.args.cores);
+ let arms = channel
+ .tasks
+ .iter()
+ .map(|name| {
+ let task = &app.software_tasks[name];
+ let cfgs = &task.cfgs;
+ let fq = util::fq_ident(name);
+ let inputs = util::inputs_ident(name);
+ let (_, tupled, pats, _) = util::regroup_inputs(&task.inputs);
- let variants = channel
- .tasks
- .iter()
- .map(|name| {
- let cfgs = &app.software_tasks[name].cfgs;
+ let (let_instant, instant) = if app.uses_schedule() {
+ let instants = util::instants_ident(name);
- quote!(
- #(#cfgs)*
- #name
- )
- })
- .collect::<Vec<_>>();
-
- let doc = format!(
- "Software tasks spawned from core #{} to be dispatched at priority level {} by core #{}",
- sender, level, receiver,
- );
- let t = util::spawn_t_ident(receiver, level, sender);
- items.push(quote!(
- #[allow(non_camel_case_types)]
- #[derive(Clone, Copy)]
- #[doc = #doc]
- enum #t {
- #(#variants,)*
- }
- ));
-
- let n = util::capacity_typenum(channel.capacity, true);
- let rq = util::rq_ident(receiver, level, sender);
- let (rq_attr, rq_ty, rq_expr, section) = if sender == receiver {
(
- cfg_sender.clone(),
- quote!(rtic::export::SCRQ<#t, #n>),
- quote!(rtic::export::Queue(unsafe {
- rtic::export::iQueue::u8_sc()
- })),
- util::link_section("bss", sender),
+ quote!(
+ let instant =
+ #instants.get_unchecked(usize::from(index)).as_ptr().read();
+ ),
+ quote!(, instant),
)
} else {
- let shared = if cfg!(feature = "heterogeneous") {
- Some(quote!(#[rtic::export::shared]))
- } else {
- None
- };
-
- (
- shared,
- quote!(rtic::export::MCRQ<#t, #n>),
- quote!(rtic::export::Queue(rtic::export::iQueue::u8())),
- None,
- )
+ (quote!(), quote!())
};
- let doc = format!(
- "Queue of tasks sent by core #{} ready to be dispatched by core #{} at priority level {}",
- sender,
- receiver,
- level
- );
- items.push(quote!(
- #[doc = #doc]
- #rq_attr
- #section
- static mut #rq: #rq_ty = #rq_expr;
- ));
-
- if let Some(ceiling) = channel.ceiling {
- items.push(quote!(
- #cfg_sender
- struct #rq<'a> {
- priority: &'a rtic::export::Priority,
- }
- ));
-
- items.push(util::impl_mutex(
- extra,
- &[],
- cfg_sender.as_ref(),
- false,
- &rq,
- rq_ty,
- ceiling,
- quote!(&mut #rq),
- ));
- }
-
- let arms = channel
- .tasks
- .iter()
- .map(|name| {
- let task = &app.software_tasks[name];
- let cfgs = &task.cfgs;
- let fq = util::fq_ident(name, sender);
- let inputs = util::inputs_ident(name, sender);
- let (_, tupled, pats, _) = util::regroup_inputs(&task.inputs);
-
- let (let_instant, instant) = if app.uses_schedule(receiver) {
- let instants = util::instants_ident(name, sender);
-
- (
- quote!(
- let instant =
- #instants.get_unchecked(usize::from(index)).as_ptr().read();
- ),
- quote!(, instant),
- )
- } else {
- (quote!(), quote!())
- };
-
- let locals_new = if task.locals.is_empty() {
- quote!()
- } else {
- quote!(#name::Locals::new(),)
- };
+ let locals_new = if task.locals.is_empty() {
+ quote!()
+ } else {
+ quote!(#name::Locals::new(),)
+ };
- quote!(
- #(#cfgs)*
- #t::#name => {
- let #tupled =
- #inputs.get_unchecked(usize::from(index)).as_ptr().read();
- #let_instant
- #fq.split().0.enqueue_unchecked(index);
- let priority = &rtic::export::Priority::new(PRIORITY);
- crate::#name(
- #locals_new
- #name::Context::new(priority #instant)
- #(,#pats)*
- )
- }
+ quote!(
+ #(#cfgs)*
+ #t::#name => {
+ let #tupled =
+ #inputs.get_unchecked(usize::from(index)).as_ptr().read();
+ #let_instant
+ #fq.split().0.enqueue_unchecked(index);
+ let priority = &rtic::export::Priority::new(PRIORITY);
+ crate::#name(
+ #locals_new
+ #name::Context::new(priority #instant)
+ #(,#pats)*
)
- })
- .collect::<Vec<_>>();
-
- stmts.push(quote!(
- while let Some((task, index)) = #rq.split().1.dequeue() {
- match task {
- #(#arms)*
- }
}
- ));
- }
-
- let doc = format!(
- "Interrupt handler used by core #{} to dispatch tasks at priority {}",
- receiver, level
- );
- let cfg_receiver = util::cfg_core(receiver, app.args.cores);
- let section = util::link_section("text", receiver);
- let interrupt = util::suffixed(&interrupts[&level].to_string(), receiver);
- items.push(quote!(
- #[allow(non_snake_case)]
- #[doc = #doc]
- #[no_mangle]
- #cfg_receiver
- #section
- unsafe fn #interrupt() {
- /// The priority of this interrupt handler
- const PRIORITY: u8 = #level;
-
- rtic::export::run(PRIORITY, || {
- #(#stmts)*
- });
+ )
+ })
+ .collect::<Vec<_>>();
+
+ stmts.push(quote!(
+ while let Some((task, index)) = #rq.split().1.dequeue() {
+ match task {
+ #(#arms)*
}
- ));
- }
+ }
+ ));
+
+ let doc = format!("Interrupt handler to dispatch tasks at priority {}", level);
+ let interrupt = util::suffixed(&interrupts[&level].to_string());
+ items.push(quote!(
+ #[allow(non_snake_case)]
+ #[doc = #doc]
+ #[no_mangle]
+ unsafe fn #interrupt() {
+ /// The priority of this interrupt handler
+ const PRIORITY: u8 = #level;
+
+ rtic::export::run(PRIORITY, || {
+ #(#stmts)*
+ });
+ }
+ ));
}
items
diff --git a/macros/src/codegen/hardware_tasks.rs b/macros/src/codegen/hardware_tasks.rs
index 453dbccb..25f1df41 100644
--- a/macros/src/codegen/hardware_tasks.rs
+++ b/macros/src/codegen/hardware_tasks.rs
@@ -1,11 +1,11 @@
use proc_macro2::TokenStream as TokenStream2;
-use quote::quote;
+use quote::{format_ident, quote};
use rtic_syntax::{ast::App, Context};
use crate::{
analyze::Analysis,
check::Extra,
- codegen::{locals, module, resources_struct, util},
+ codegen::{locals, module, resources_struct},
};
/// Generate support code for hardware tasks (`#[exception]`s and `#[interrupt]`s)
@@ -14,7 +14,7 @@ pub fn codegen(
analysis: &Analysis,
extra: &Extra,
) -> (
- // const_app_hardware_tasks -- interrupt handlers and `${task}Resources` constructors
+ // mod_app_hardware_tasks -- interrupt handlers and `${task}Resources` constructors
Vec<TokenStream2>,
// root_hardware_tasks -- items that must be placed in the root of the crate:
// - `${task}Locals` structs
@@ -23,16 +23,16 @@ pub fn codegen(
Vec<TokenStream2>,
// user_hardware_tasks -- the `#[task]` functions written by the user
Vec<TokenStream2>,
+ // user_hardware_tasks_imports -- the imports for `#[task]` functions written by the user
+ Vec<TokenStream2>,
) {
- let mut const_app = vec![];
+ let mut mod_app = vec![];
let mut root = vec![];
let mut user_tasks = vec![];
+ let mut hardware_tasks_imports = vec![];
for (name, task) in &app.hardware_tasks {
- let core = task.args.core;
- let cfg_core = util::cfg_core(core, app.args.cores);
-
- let (let_instant, instant) = if app.uses_schedule(core) {
+ let (let_instant, instant) = if app.uses_schedule() {
let m = extra.monotonic();
(
@@ -49,19 +49,12 @@ pub fn codegen(
quote!(#name::Locals::new(),)
};
- let symbol = if cfg!(feature = "homogeneous") {
- util::suffixed(&task.args.binds.to_string(), core)
- } else {
- task.args.binds.clone()
- };
+ let symbol = task.args.binds.clone();
let priority = task.args.priority;
- let section = util::link_section("text", core);
- const_app.push(quote!(
+ mod_app.push(quote!(
#[allow(non_snake_case)]
#[no_mangle]
- #section
- #cfg_core
unsafe fn #symbol() {
const PRIORITY: u8 = #priority;
@@ -88,9 +81,16 @@ pub fn codegen(
analysis,
);
+ // Add resources to imports
+ let name_res = format_ident!("{}Resources", name);
+ hardware_tasks_imports.push(quote!(
+ #[allow(non_snake_case)]
+ use super::#name_res;
+ ));
+
root.push(item);
- const_app.push(constructor);
+ mod_app.push(constructor);
}
root.push(module::codegen(
@@ -103,8 +103,7 @@ pub fn codegen(
// `${task}Locals`
let mut locals_pat = None;
if !task.locals.is_empty() {
- let (struct_, pat) =
- locals::codegen(Context::HardwareTask(name), &task.locals, core, app);
+ let (struct_, pat) = locals::codegen(Context::HardwareTask(name), &task.locals, app);
root.push(struct_);
locals_pat = Some(pat);
@@ -113,20 +112,23 @@ pub fn codegen(
let attrs = &task.attrs;
let context = &task.context;
let stmts = &task.stmts;
- let section = util::link_section("text", core);
- // XXX shouldn't this have a cfg_core?
let locals_pat = locals_pat.iter();
user_tasks.push(quote!(
#(#attrs)*
#[allow(non_snake_case)]
- #section
fn #name(#(#locals_pat,)* #context: #name::Context) {
use rtic::Mutex as _;
#(#stmts)*
}
));
+
+ hardware_tasks_imports.push(quote!(
+ #(#attrs)*
+ #[allow(non_snake_case)]
+ use super::#name;
+ ));
}
- (const_app, root, user_tasks)
+ (mod_app, root, user_tasks, hardware_tasks_imports)
}
diff --git a/macros/src/codegen/idle.rs b/macros/src/codegen/idle.rs
index 032c8ade..2e2932d7 100644
--- a/macros/src/codegen/idle.rs
+++ b/macros/src/codegen/idle.rs
@@ -1,21 +1,20 @@
use proc_macro2::TokenStream as TokenStream2;
-use quote::quote;
+use quote::{format_ident, quote};
use rtic_syntax::{ast::App, Context};
use crate::{
analyze::Analysis,
check::Extra,
- codegen::{locals, module, resources_struct, util},
+ codegen::{locals, module, resources_struct},
};
/// Generates support code for `#[idle]` functions
pub fn codegen(
- core: u8,
app: &App,
analysis: &Analysis,
extra: &Extra,
) -> (
- // const_app_idle -- the `${idle}Resources` constructor
+ // mod_app_idle -- the `${idle}Resources` constructor
Option<TokenStream2>,
// root_idle -- items that must be placed in the root of the crate:
// - the `${idle}Locals` struct
@@ -24,52 +23,65 @@ pub fn codegen(
Vec<TokenStream2>,
// user_idle
Option<TokenStream2>,
+ // user_idle_imports
+ Vec<TokenStream2>,
// call_idle
TokenStream2,
) {
- if let Some(idle) = app.idles.get(&core) {
+ if app.idles.len() > 0 {
+ let idle = &app.idles.first().unwrap();
let mut needs_lt = false;
- let mut const_app = None;
+ let mut mod_app = None;
let mut root_idle = vec![];
let mut locals_pat = None;
let mut locals_new = None;
+ let mut user_idle_imports = vec![];
+
+ let name = &idle.name;
+
if !idle.args.resources.is_empty() {
let (item, constructor) =
- resources_struct::codegen(Context::Idle(core), 0, &mut needs_lt, app, analysis);
+ resources_struct::codegen(Context::Idle, 0, &mut needs_lt, app, analysis);
root_idle.push(item);
- const_app = Some(constructor);
+ mod_app = Some(constructor);
+
+ let name_resource = format_ident!("{}Resources", name);
+ user_idle_imports.push(quote!(
+ #[allow(non_snake_case)]
+ use super::#name_resource;
+ ));
}
- let name = &idle.name;
if !idle.locals.is_empty() {
- let (locals, pat) = locals::codegen(Context::Idle(core), &idle.locals, core, app);
+ let (locals, pat) = locals::codegen(Context::Idle, &idle.locals, app);
locals_new = Some(quote!(#name::Locals::new()));
locals_pat = Some(pat);
root_idle.push(locals);
}
- root_idle.push(module::codegen(Context::Idle(core), needs_lt, app, extra));
+ root_idle.push(module::codegen(Context::Idle, needs_lt, app, extra));
- let cfg_core = util::cfg_core(core, app.args.cores);
let attrs = &idle.attrs;
let context = &idle.context;
let stmts = &idle.stmts;
- let section = util::link_section("text", core);
let locals_pat = locals_pat.iter();
let user_idle = Some(quote!(
#(#attrs)*
#[allow(non_snake_case)]
- #cfg_core
- #section
fn #name(#(#locals_pat,)* #context: #name::Context) -> ! {
use rtic::Mutex as _;
#(#stmts)*
}
));
+ user_idle_imports.push(quote!(
+ #(#attrs)*
+ #[allow(non_snake_case)]
+ use super::#name;
+ ));
let locals_new = locals_new.iter();
let call_idle = quote!(crate::#name(
@@ -77,12 +89,13 @@ pub fn codegen(
#name::Context::new(&rtic::export::Priority::new(0))
));
- (const_app, root_idle, user_idle, call_idle)
+ (mod_app, root_idle, user_idle, user_idle_imports, call_idle)
} else {
(
None,
vec![],
None,
+ vec![],
quote!(loop {
rtic::export::wfi()
}),
diff --git a/macros/src/codegen/init.rs b/macros/src/codegen/init.rs
index fa273fee..8942439b 100644
--- a/macros/src/codegen/init.rs
+++ b/macros/src/codegen/init.rs
@@ -1,5 +1,5 @@
use proc_macro2::TokenStream as TokenStream2;
-use quote::quote;
+use quote::{format_ident, quote};
use rtic_syntax::{ast::App, Context};
use crate::{
@@ -10,12 +10,11 @@ use crate::{
/// Generates support code for `#[init]` functions
pub fn codegen(
- core: u8,
app: &App,
analysis: &Analysis,
extra: &Extra,
) -> (
- // const_app_idle -- the `${init}Resources` constructor
+ // mod_app_idle -- the `${init}Resources` constructor
Option<TokenStream2>,
// root_init -- items that must be placed in the root of the crate:
// - the `${init}Locals` struct
@@ -25,58 +24,55 @@ pub fn codegen(
Vec<TokenStream2>,
// user_init -- the `#[init]` function written by the user
Option<TokenStream2>,
+ // user_init_imports -- the imports for `#[init]` functio written by the user
+ Vec<TokenStream2>,
// call_init -- the call to the user `#[init]` if there's one
Option<TokenStream2>,
) {
- if let Some(init) = app.inits.get(&core) {
- let cfg_core = util::cfg_core(core, app.args.cores);
+ if app.inits.len() > 0 {
+ let init = &app.inits.first().unwrap();
let mut needs_lt = false;
let name = &init.name;
let mut root_init = vec![];
- let ret = {
- let late_fields = analysis
- .late_resources
- .get(&core)
- .map(|resources| {
- resources
- .iter()
- .map(|name| {
- let ty = &app.late_resources[name].ty;
- let cfgs = &app.late_resources[name].cfgs;
-
- quote!(
- #(#cfgs)*
- pub #name: #ty
- )
- })
- .collect::<Vec<_>>()
+ let late_fields = analysis
+ .late_resources
+ .iter()
+ .flat_map(|resources| {
+ resources.iter().map(|name| {
+ let ty = &app.late_resources[name].ty;
+ let cfgs = &app.late_resources[name].cfgs;
+
+ quote!(
+ #(#cfgs)*
+ pub #name: #ty
+ )
})
- .unwrap_or(vec![]);
+ })
+ .collect::<Vec<_>>();
- if !late_fields.is_empty() {
- let late_resources = util::late_resources_ident(&name);
+ let mut user_init_imports = vec![];
+ let late_resources = util::late_resources_ident(&name);
- root_init.push(quote!(
- /// Resources initialized at runtime
- #cfg_core
- #[allow(non_snake_case)]
- pub struct #late_resources {
- #(#late_fields),*
- }
- ));
-
- Some(quote!(-> #name::LateResources))
- } else {
- None
+ root_init.push(quote!(
+ /// Resources initialized at runtime
+ #[allow(non_snake_case)]
+ pub struct #late_resources {
+ #(#late_fields),*
}
- };
+ ));
+
+ let name_late = format_ident!("{}LateResources", name);
+ user_init_imports.push(quote!(
+ #[allow(non_snake_case)]
+ use super::#name_late;
+ ));
let mut locals_pat = None;
let mut locals_new = None;
if !init.locals.is_empty() {
- let (struct_, pat) = locals::codegen(Context::Init(core), &init.locals, core, app);
+ let (struct_, pat) = locals::codegen(Context::Init, &init.locals, app);
locals_new = Some(quote!(#name::Locals::new()));
locals_pat = Some(pat);
@@ -86,25 +82,33 @@ pub fn codegen(
let context = &init.context;
let attrs = &init.attrs;
let stmts = &init.stmts;
- let section = util::link_section("text", core);
let locals_pat = locals_pat.iter();
let user_init = Some(quote!(
#(#attrs)*
- #cfg_core
#[allow(non_snake_case)]
- #section
- fn #name(#(#locals_pat,)* #context: #name::Context) #ret {
+ fn #name(#(#locals_pat,)* #context: #name::Context) -> #name::LateResources {
#(#stmts)*
}
));
+ user_init_imports.push(quote!(
+ #(#attrs)*
+ #[allow(non_snake_case)]
+ use super::#name;
+ ));
- let mut const_app = None;
+ let mut mod_app = None;
if !init.args.resources.is_empty() {
let (item, constructor) =
- resources_struct::codegen(Context::Init(core), 0, &mut needs_lt, app, analysis);
+ resources_struct::codegen(Context::Init, 0, &mut needs_lt, app, analysis);
root_init.push(item);
- const_app = Some(constructor);
+ mod_app = Some(constructor);
+
+ let name_late = format_ident!("{}Resources", name);
+ user_init_imports.push(quote!(
+ #[allow(non_snake_case)]
+ use super::#name_late;
+ ));
}
let locals_new = locals_new.iter();
@@ -112,10 +116,10 @@ pub fn codegen(
quote!(let late = crate::#name(#(#locals_new,)* #name::Context::new(core.into()));),
);
- root_init.push(module::codegen(Context::Init(core), needs_lt, app, extra));
+ root_init.push(module::codegen(Context::Init, needs_lt, app, extra));
- (const_app, root_init, user_init, call_init)
+ (mod_app, root_init, user_init, user_init_imports, call_init)
} else {
- (None, vec![], None, None)
+ (None, vec![], None, vec![], None)
}
}
diff --git a/macros/src/codegen/locals.rs b/macros/src/codegen/locals.rs
index 127f4b09..336c0b21 100644
--- a/macros/src/codegen/locals.rs
+++ b/macros/src/codegen/locals.rs
@@ -2,7 +2,7 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use rtic_syntax::{
ast::{App, Local},
- Context, Core, Map,
+ Context, Map,
};
use crate::codegen::util;
@@ -10,7 +10,6 @@ use crate::codegen::util;
pub fn codegen(
ctxt: Context,
locals: &Map<Local>,
- core: Core,
app: &App,
) -> (
// locals
@@ -42,11 +41,6 @@ pub fn codegen(
let cfgs = &local.cfgs;
has_cfgs |= !cfgs.is_empty();
- let section = if local.shared && cfg!(feature = "heterogeneous") {
- Some(quote!(#[rtic::export::shared]))
- } else {
- util::link_section("data", core)
- };
let expr = &local.expr;
let ty = &local.ty;
fields.push(quote!(
@@ -55,7 +49,6 @@ pub fn codegen(
));
items.push(quote!(
#(#cfgs)*
- #section
static mut #name: #ty = #expr
));
values.push(quote!(
diff --git a/macros/src/codegen/module.rs b/macros/src/codegen/module.rs
index 1b21209f..2e51e7db 100644
--- a/macros/src/codegen/module.rs
+++ b/macros/src/codegen/module.rs
@@ -11,12 +11,11 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
let name = ctxt.ident(app);
- let core = ctxt.core(app);
let mut needs_instant = false;
let mut lt = None;
match ctxt {
- Context::Init(core) => {
- if app.uses_schedule(core) {
+ Context::Init => {
+ if app.uses_schedule() {
let m = extra.monotonic();
fields.push(quote!(
@@ -37,7 +36,7 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
));
}
- if extra.peripherals == Some(core) {
+ if extra.peripherals {
let device = extra.device;
fields.push(quote!(
@@ -48,13 +47,21 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
values.push(quote!(device: #device::Peripherals::steal()));
}
+ lt = Some(quote!('a));
+ fields.push(quote!(
+ /// Critical section token for init
+ pub cs: rtic::export::CriticalSection<#lt>
+ ));
+
+ values.push(quote!(cs: rtic::export::CriticalSection::new()));
+
values.push(quote!(core));
}
- Context::Idle(..) => {}
+ Context::Idle => {}
Context::HardwareTask(..) => {
- if app.uses_schedule(core) {
+ if app.uses_schedule() {
let m = extra.monotonic();
fields.push(quote!(
@@ -69,7 +76,7 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
}
Context::SoftwareTask(..) => {
- if app.uses_schedule(core) {
+ if app.uses_schedule() {
let m = extra.monotonic();
fields.push(quote!(
@@ -205,7 +212,7 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
values.push(quote!(spawn: Spawn { priority }));
} else {
- let instant_field = if app.uses_schedule(core) {
+ let instant_field = if app.uses_schedule() {
let m = extra.monotonic();
needs_instant = true;
@@ -252,27 +259,25 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
}
}
- if let Context::Init(core) = ctxt {
- let init = &app.inits[&core];
- if init.returns_late_resources {
- let late_resources = util::late_resources_ident(&init.name);
+ if let Context::Init = ctxt {
+ let init = &app.inits.first().unwrap();
+ let late_resources = util::late_resources_ident(&init.name);
- items.push(quote!(
- #[doc(inline)]
- pub use super::#late_resources as LateResources;
- ));
- }
+ items.push(quote!(
+ #[doc(inline)]
+ pub use super::#late_resources as LateResources;
+ ));
}
let doc = match ctxt {
- Context::Idle(_) => "Idle loop",
- Context::Init(_) => "Initialization function",
+ Context::Idle => "Idle loop",
+ Context::Init => "Initialization function",
Context::HardwareTask(_) => "Hardware task",
Context::SoftwareTask(_) => "Software task",
};
let core = if ctxt.is_init() {
- if app.uses_schedule(core) {
+ if app.uses_schedule() {
Some(quote!(core: rtic::Peripherals,))
} else {
Some(quote!(core: rtic::export::Peripherals,))
@@ -312,12 +317,9 @@ pub fn codegen(ctxt: Context, resources_tick: bool, app: &App, extra: &Extra) ->
));
if !items.is_empty() {
- let cfg_core = util::cfg_core(ctxt.core(app), app.args.cores);
-
quote!(
#[allow(non_snake_case)]
#[doc = #doc]
- #cfg_core
pub mod #name {
#(#items)*
}
diff --git a/macros/src/codegen/post_init.rs b/macros/src/codegen/post_init.rs
index 0c740e85..c35c6976 100644
--- a/macros/src/codegen/post_init.rs
+++ b/macros/src/codegen/post_init.rs
@@ -2,22 +2,17 @@ use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use rtic_syntax::ast::App;
-use crate::{analyze::Analysis, check::Extra, codegen::util};
+use crate::analyze::Analysis;
/// Generates code that runs after `#[init]` returns
-pub fn codegen(
- core: u8,
- app: &App,
- analysis: &Analysis,
- extra: &Extra,
-) -> (Vec<TokenStream2>, Vec<TokenStream2>) {
- let mut const_app = vec![];
+pub fn codegen(app: &App, analysis: &Analysis) -> Vec<TokenStream2> {
let mut stmts = vec![];
- // initialize late resources
- if let Some(late_resources) = analysis.late_resources.get(&core) {
- for name in late_resources {
- // if it's live
+ // Initialize late resources
+ if analysis.late_resources.len() > 0 {
+ // BTreeSet wrapped in a vector
+ for name in analysis.late_resources.first().unwrap() {
+ // If it's live
let cfgs = app.late_resources[name].cfgs.clone();
if analysis.locations.get(name).is_some() {
// Need to also include the cfgs
@@ -29,134 +24,8 @@ pub fn codegen(
}
}
- if analysis.timer_queues.is_empty() {
- // cross-initialization barriers -- notify *other* cores that their resources have been
- // initialized
- for (user, initializers) in &analysis.initialization_barriers {
- if !initializers.contains(&core) {
- continue;
- }
-
- let ib = util::init_barrier(*user);
- let shared = if cfg!(feature = "heterogeneous") {
- Some(quote!(
- #[rtic::export::shared]
- ))
- } else {
- None
- };
-
- const_app.push(quote!(
- #shared
- static #ib: rtic::export::Barrier = rtic::export::Barrier::new();
- ));
-
- stmts.push(quote!(
- #ib.release();
- ));
- }
-
- // then wait until the other cores have initialized *our* resources
- if analysis.initialization_barriers.contains_key(&core) {
- let ib = util::init_barrier(core);
-
- stmts.push(quote!(
- #ib.wait();
- ));
- }
-
- // cross-spawn barriers: wait until other cores are ready to receive messages
- for (&receiver, senders) in &analysis.spawn_barriers {
- if senders.get(&core) == Some(&false) {
- let sb = util::spawn_barrier(receiver);
-
- stmts.push(quote!(
- #sb.wait();
- ));
- }
- }
- } else {
- // if the `schedule` API is used then we'll synchronize all cores to leave the
- // `init`-ialization phase at the same time. In this case the rendezvous barrier makes the
- // cross-initialization and spawn barriers unnecessary
-
- let m = extra.monotonic();
-
- if analysis.timer_queues.len() == 1 {
- // reset the monotonic timer / counter
- stmts.push(quote!(
- <#m as rtic::Monotonic>::reset();
- ));
- } else {
- // in the multi-core case we need a rendezvous (RV) barrier between *all* the cores that
- // use the `schedule` API; otherwise one of the cores could observe the before-reset
- // value of the monotonic counter
- // (this may be easier to implement with `AtomicU8.fetch_sub` but that API is not
- // available on ARMv6-M)
-
- // this core will reset the monotonic counter
- const FIRST: u8 = 0;
-
- if core == FIRST {
- for &i in analysis.timer_queues.keys() {
- let rv = util::rendezvous_ident(i);
- let shared = if cfg!(feature = "heterogeneous") {
- Some(quote!(
- #[rtic::export::shared]
- ))
- } else {
- None
- };
-
- const_app.push(quote!(
- #shared
- static #rv: rtic::export::Barrier = rtic::export::Barrier::new();
- ));
-
- // wait until all the other cores have reached the RV point
- if i != FIRST {
- stmts.push(quote!(
- #rv.wait();
- ));
- }
- }
-
- let rv = util::rendezvous_ident(core);
- stmts.push(quote!(
- // the compiler fences are used to prevent `reset` from being re-ordering wrt to
- // the atomic operations -- we don't know if `reset` contains load or store
- // operations
-
- core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
-
- // reset the counter
- <#m as rtic::Monotonic>::reset();
-
- core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
-
- // now unblock all the other cores
- #rv.release();
- ));
- } else {
- let rv = util::rendezvous_ident(core);
-
- // let the first core know that we have reached the RV point
- stmts.push(quote!(
- #rv.release();
- ));
-
- let rv = util::rendezvous_ident(FIRST);
-
- // wait until the first core has reset the monotonic timer
- stmts.push(quote!(
- #rv.wait();
- ));
- }
- }
- }
-
- // enable the interrupts -- this completes the `init`-ialization phase
+ // Enable the interrupts -- this completes the `init`-ialization phase
stmts.push(quote!(rtic::export::interrupt::enable();));
- (const_app, stmts)
+ stmts
}
diff --git a/macros/src/codegen/pre_init.rs b/macros/src/codegen/pre_init.rs
index 8aae5998..9c5f35ec 100644
--- a/macros/src/codegen/pre_init.rs
+++ b/macros/src/codegen/pre_init.rs
@@ -5,76 +5,52 @@ use rtic_syntax::ast::App;
use crate::{analyze::Analysis, check::Extra, codegen::util};
/// Generates code that runs before `#[init]`
-pub fn codegen(
- core: u8,
- app: &App,
- analysis: &Analysis,
- extra: &Extra,
-) -> (
- // `const_app_pre_init` -- `static` variables for barriers
- Vec<TokenStream2>,
- // `pre_init_stmts`
- Vec<TokenStream2>,
-) {
- let mut const_app = vec![];
+pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
let mut stmts = vec![];
- // disable interrupts -- `init` must run with interrupts disabled
+ // Disable interrupts -- `init` must run with interrupts disabled
stmts.push(quote!(rtic::export::interrupt::disable();));
- // populate this core `FreeQueue`s
- for (name, senders) in &analysis.free_queues {
+ // Populate the FreeQueue
+ for fq in &analysis.free_queues {
+ // Get the task name
+ let name = fq.0;
let task = &app.software_tasks[name];
let cap = task.args.capacity;
- for &sender in senders.keys() {
- if sender == core {
- let fq = util::fq_ident(name, sender);
+ let fq_ident = util::fq_ident(name);
- stmts.push(quote!(
- (0..#cap).for_each(|i| #fq.enqueue_unchecked(i));
- ));
- }
- }
- }
-
- if app.args.cores == 1 {
- stmts.push(quote!(
- // To set the variable in cortex_m so the peripherals cannot be taken multiple times
- let peripherals = cortex_m::Peripherals::steal();
- let mut core: rtic::export::Peripherals = peripherals.into();
- ));
- } else {
stmts.push(quote!(
- // NOTE(transmute) to avoid debug_assertion in multi-core mode
- // (This code will go away when we drop multi-core mode)
- let mut core: rtic::export::Peripherals = core::mem::transmute(());
+ (0..#cap).for_each(|i| #fq_ident.enqueue_unchecked(i));
));
}
+ stmts.push(quote!(
+ // To set the variable in cortex_m so the peripherals cannot be taken multiple times
+ let mut core: rtic::export::Peripherals = rtic::export::Peripherals::steal().into();
+ ));
+
let device = extra.device;
let nvic_prio_bits = quote!(#device::NVIC_PRIO_BITS);
- // unmask interrupts and set their priorities
+ // Unmask interrupts and set their priorities
for (&priority, name) in analysis
.interrupts
- .get(&core)
.iter()
- .flat_map(|interrupts| *interrupts)
.chain(app.hardware_tasks.values().flat_map(|task| {
if !util::is_exception(&task.args.binds) {
Some((&task.args.priority, &task.args.binds))
} else {
- // we do exceptions in another pass
+ // We do exceptions in another pass
None
}
}))
{
- // compile time assert that this priority is supported by the device
+ // Compile time assert that this priority is supported by the device
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
// NOTE this also checks that the interrupt exists in the `Interrupt` enumeration
- let interrupt = util::interrupt_ident(core, app.args.cores);
+ let interrupt = util::interrupt_ident();
stmts.push(quote!(
core.NVIC.set_priority(
#device::#interrupt::#name,
@@ -87,30 +63,7 @@ pub fn codegen(
stmts.push(quote!(rtic::export::NVIC::unmask(#device::#interrupt::#name);));
}
- // cross-spawn barriers: now that priorities have been set and the interrupts have been unmasked
- // we are ready to receive messages from *other* cores
- if analysis.spawn_barriers.contains_key(&core) {
- let sb = util::spawn_barrier(core);
- let shared = if cfg!(feature = "heterogeneous") {
- Some(quote!(
- #[rtic::export::shared]
- ))
- } else {
- None
- };
-
- const_app.push(quote!(
- #shared
- static #sb: rtic::export::Barrier = rtic::export::Barrier::new();
- ));
-
- // unblock cores that may send us a message
- stmts.push(quote!(
- #sb.release();
- ));
- }
-
- // set exception priorities
+ // Set exception priorities
for (name, priority) in app.hardware_tasks.values().filter_map(|task| {
if util::is_exception(&task.args.binds) {
Some((&task.args.binds, task.args.priority))
@@ -118,7 +71,7 @@ pub fn codegen(
None
}
}) {
- // compile time assert that this priority is supported by the device
+ // Compile time assert that this priority is supported by the device
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
stmts.push(quote!(core.SCB.set_priority(
@@ -127,11 +80,11 @@ pub fn codegen(
);));
}
- // initialize the SysTick
- if let Some(tq) = analysis.timer_queues.get(&core) {
+ // Initialize the SysTick if there exist a TimerQueue
+ if let Some(tq) = analysis.timer_queues.first() {
let priority = tq.priority;
- // compile time assert that this priority is supported by the device
+ // Compile time assert that this priority is supported by the device
stmts.push(quote!(let _ = [(); ((1 << #nvic_prio_bits) - #priority as usize)];));
stmts.push(quote!(core.SCB.set_priority(
@@ -146,23 +99,11 @@ pub fn codegen(
));
}
- // if there's no user `#[idle]` then optimize returning from interrupt handlers
- if app.idles.get(&core).is_none() {
+ // If there's no user `#[idle]` then optimize returning from interrupt handlers
+ if app.idles.is_empty() {
// Set SLEEPONEXIT bit to enter sleep mode when returning from ISR
stmts.push(quote!(core.SCB.scr.modify(|r| r | 1 << 1);));
}
- // cross-spawn barriers: wait until other cores are ready to receive messages
- for (&receiver, senders) in &analysis.spawn_barriers {
- // only block here if `init` can send messages to `receiver`
- if senders.get(&core) == Some(&true) {
- let sb = util::spawn_barrier(receiver);
-
- stmts.push(quote!(
- #sb.wait();
- ));
- }
- }
-
- (const_app, stmts)
+ stmts
}
diff --git a/macros/src/codegen/resources.rs b/macros/src/codegen/resources.rs
index 0bec3e5a..38ea5245 100644
--- a/macros/src/codegen/resources.rs
+++ b/macros/src/codegen/resources.rs
@@ -1,9 +1,6 @@
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
-use rtic_syntax::{
- analyze::{Location, Ownership},
- ast::App,
-};
+use rtic_syntax::{analyze::Ownership, ast::App};
use crate::{analyze::Analysis, check::Extra, codegen::util};
@@ -13,45 +10,26 @@ pub fn codegen(
analysis: &Analysis,
extra: &Extra,
) -> (
- // const_app -- the `static [mut]` variables behind the proxies
+ // mod_app -- the `static [mut]` variables behind the proxies
Vec<TokenStream2>,
// mod_resources -- the `resources` module
TokenStream2,
+ // mod_resources_imports -- the `resources` module imports
+ Vec<TokenStream2>,
) {
- let mut const_app = vec![];
+ let mut mod_app = vec![];
let mut mod_resources = vec![];
+ let mut mod_resources_imports = vec![];
- for (name, res, expr, loc) in app.resources(analysis) {
+ for (name, res, expr, _) in app.resources(analysis) {
let cfgs = &res.cfgs;
let ty = &res.ty;
{
- let (loc_attr, section) = match loc {
- Location::Owned {
- core,
- cross_initialized: false,
- } => (
- util::cfg_core(*core, app.args.cores),
- if expr.is_none() {
- util::link_section_uninit(Some(*core))
- } else {
- util::link_section("data", *core)
- },
- ),
-
- // shared `static`s and cross-initialized resources need to be in `.shared` memory
- _ => (
- if cfg!(feature = "heterogeneous") {
- Some(quote!(#[rtic::export::shared]))
- } else {
- None
- },
- if expr.is_none() {
- util::link_section_uninit(None)
- } else {
- None
- },
- ),
+ let section = if expr.is_none() {
+ util::link_section_uninit(true)
+ } else {
+ None
};
let (ty, expr) = if let Some(expr) = expr {
@@ -64,29 +42,24 @@ pub fn codegen(
};
let attrs = &res.attrs;
- const_app.push(quote!(
+ mod_app.push(quote!(
#[allow(non_upper_case_globals)]
#(#attrs)*
#(#cfgs)*
- #loc_attr
#section
static mut #name: #ty = #expr;
));
}
if let Some(Ownership::Contended { ceiling }) = analysis.ownerships.get(name) {
- let cfg_core = util::cfg_core(loc.core().expect("UNREACHABLE"), app.args.cores);
-
mod_resources.push(quote!(
#[allow(non_camel_case_types)]
#(#cfgs)*
- #cfg_core
pub struct #name<'a> {
priority: &'a Priority,
}
#(#cfgs)*
- #cfg_core
impl<'a> #name<'a> {
#[inline(always)]
pub unsafe fn new(priority: &'a Priority) -> Self {
@@ -112,10 +85,15 @@ pub fn codegen(
)
};
- const_app.push(util::impl_mutex(
+ mod_resources_imports.push(quote!(
+ #[allow(non_camel_case_types)]
+ #(#cfgs)*
+ use super::resources::#name;
+ ));
+
+ mod_app.push(util::impl_mutex(
extra,
cfgs,
- cfg_core.as_ref(),
true,
name,
quote!(#ty),
@@ -128,6 +106,11 @@ pub fn codegen(
let mod_resources = if mod_resources.is_empty() {
quote!()
} else {
+ // Also import the resource module
+ mod_resources_imports.push(quote!(
+ use super::resources;
+ ));
+
quote!(mod resources {
use rtic::export::Priority;
@@ -135,5 +118,5 @@ pub fn codegen(
})
};
- (const_app, mod_resources)
+ (mod_app, mod_resources, mod_resources_imports)
}
diff --git a/macros/src/codegen/resources_struct.rs b/macros/src/codegen/resources_struct.rs
index 994e751c..92d5b666 100644
--- a/macros/src/codegen/resources_struct.rs
+++ b/macros/src/codegen/resources_struct.rs
@@ -14,8 +14,8 @@ pub fn codegen(
let mut lt = None;
let resources = match ctxt {
- Context::Init(core) => &app.inits[&core].args.resources,
- Context::Idle(core) => &app.idles[&core].args.resources,
+ Context::Init => &app.inits.first().unwrap().args.resources,
+ Context::Idle => &app.idles.first().unwrap().args.resources,
Context::HardwareTask(name) => &app.hardware_tasks[name].args.resources,
Context::SoftwareTask(name) => &app.software_tasks[name].args.resources,
};
@@ -39,7 +39,7 @@ pub fn codegen(
if ctxt.is_init() {
if !analysis.ownerships.contains_key(name) {
- // owned by `init`
+ // Owned by `init`
fields.push(quote!(
#(#cfgs)*
pub #name: &'static #mut_ #ty
@@ -50,7 +50,7 @@ pub fn codegen(
#name: &#mut_ #name
));
} else {
- // owned by someone else
+ // Owned by someone else
lt = Some(quote!('a));
fields.push(quote!(
@@ -75,7 +75,7 @@ pub fn codegen(
pub #name: &'a #ty
));
} else {
- // resource proxy
+ // Resource proxy
lt = Some(quote!('a));
fields.push(quote!(
@@ -136,7 +136,7 @@ pub fn codegen(
if lt.is_some() {
*needs_lt = true;
- // the struct could end up empty due to `cfg`s leading to an error due to `'a` being unused
+ // The struct could end up empty due to `cfg`s leading to an error due to `'a` being unused
if has_cfgs {
fields.push(quote!(
#[doc(hidden)]
@@ -147,13 +147,9 @@ pub fn codegen(
}
}
- let core = ctxt.core(app);
- let cores = app.args.cores;
- let cfg_core = util::cfg_core(core, cores);
let doc = format!("Resources `{}` has access to", ctxt.ident(app));
let ident = util::resources_ident(ctxt, app);
let item = quote!(
- #cfg_core
#[allow(non_snake_case)]
#[doc = #doc]
pub struct #ident<#lt> {
@@ -167,10 +163,9 @@ pub fn codegen(
Some(quote!(priority: &#lt rtic::export::Priority))
};
let constructor = quote!(
- #cfg_core
impl<#lt> #ident<#lt> {
#[inline(always)]
- unsafe fn new(#arg) -> Self {
+ pub unsafe fn new(#arg) -> Self {
#ident {
#(#values,)*
}
diff --git a/macros/src/codegen/schedule.rs b/macros/src/codegen/schedule.rs
index 728d3a09..5a887496 100644
--- a/macros/src/codegen/schedule.rs
+++ b/macros/src/codegen/schedule.rs
@@ -1,4 +1,4 @@
-use std::collections::{BTreeMap, HashSet};
+use std::collections::HashSet;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
@@ -13,14 +13,11 @@ use crate::{
pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> {
let mut items = vec![];
- let mut seen = BTreeMap::<u8, HashSet<_>>::new();
+ let mut seen = HashSet::<_>::new();
for (scheduler, schedulees) in app.schedule_callers() {
let m = extra.monotonic();
let instant = quote!(<#m as rtic::Monotonic>::Instant);
- let sender = scheduler.core(app);
- let cfg_sender = util::cfg_core(sender, app.args.cores);
- let seen = seen.entry(sender).or_default();
let mut methods = vec![];
for name in schedulees {
@@ -35,29 +32,24 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> {
let body = schedule_body::codegen(scheduler, &name, app);
- let section = util::link_section("text", sender);
methods.push(quote!(
#(#cfgs)*
- #section
- fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
+ pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
#body
}
));
} else {
- let schedule = util::schedule_ident(name, sender);
+ let schedule = util::schedule_ident(name);
if !seen.contains(name) {
- // generate a `schedule_${name}_S${sender}` function
+ // Generate a `schedule_${name}_S${sender}` function
seen.insert(name);
let body = schedule_body::codegen(scheduler, &name, app);
- let section = util::link_section("text", sender);
items.push(quote!(
- #cfg_sender
#(#cfgs)*
- #section
- unsafe fn #schedule(
+ pub unsafe fn #schedule(
priority: &rtic::export::Priority,
instant: #instant
#(,#args)*
@@ -70,7 +62,7 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> {
methods.push(quote!(
#(#cfgs)*
#[inline(always)]
- fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
+ pub fn #name(&self, instant: #instant #(,#args)*) -> Result<(), #ty> {
unsafe {
#schedule(self.priority(), instant #(,#untupled)*)
}
@@ -88,7 +80,6 @@ pub fn codegen(app: &App, extra: &Extra) -> Vec<TokenStream2> {
let scheduler = scheduler.ident(app);
debug_assert!(!methods.is_empty());
items.push(quote!(
- #cfg_sender
impl<#lt> #scheduler::Schedule<#lt> {
#(#methods)*
}
diff --git a/macros/src/codegen/schedule_body.rs b/macros/src/codegen/schedule_body.rs
index 8fd026c2..644930d7 100644
--- a/macros/src/codegen/schedule_body.rs
+++ b/macros/src/codegen/schedule_body.rs
@@ -6,12 +6,10 @@ use syn::Ident;
use crate::codegen::util;
pub fn codegen(scheduler: Context, name: &Ident, app: &App) -> TokenStream2 {
- let sender = scheduler.core(app);
let schedulee = &app.software_tasks[name];
- let receiver = schedulee.args.core;
- let fq = util::fq_ident(name, sender);
- let tq = util::tq_ident(sender);
+ let fq = util::fq_ident(name);
+ let tq = util::tq_ident();
let (dequeue, enqueue) = if scheduler.is_init() {
(quote!(#fq.dequeue()), quote!(#tq.enqueue_unchecked(nr);))
} else {
@@ -21,8 +19,8 @@ pub fn codegen(scheduler: Context, name: &Ident, app: &App) -> TokenStream2 {
)
};
- let write_instant = if app.uses_schedule(receiver) {
- let instants = util::instants_ident(name, sender);
+ let write_instant = if app.uses_schedule() {
+ let instants = util::instants_ident(name);
Some(quote!(
#instants.get_unchecked_mut(usize::from(index)).as_mut_ptr().write(instant);
@@ -32,8 +30,8 @@ pub fn codegen(scheduler: Context, name: &Ident, app: &App) -> TokenStream2 {
};
let (_, tupled, _, _) = util::regroup_inputs(&schedulee.inputs);
- let inputs = util::inputs_ident(name, sender);
- let t = util::schedule_t_ident(sender);
+ let inputs = util::inputs_ident(name);
+ let t = util::schedule_t_ident();
quote!(
unsafe {
use rtic::Mutex as _;
diff --git a/macros/src/codegen/software_tasks.rs b/macros/src/codegen/software_tasks.rs
index 14a57633..4ae37e4e 100644
--- a/macros/src/codegen/software_tasks.rs
+++ b/macros/src/codegen/software_tasks.rs
@@ -1,5 +1,5 @@
use proc_macro2::TokenStream as TokenStream2;
-use quote::quote;
+use quote::{format_ident, quote};
use rtic_syntax::{ast::App, Context};
use crate::{
@@ -13,7 +13,7 @@ pub fn codegen(
analysis: &Analysis,
extra: &Extra,
) -> (
- // const_app_software_tasks -- free queues, buffers and `${task}Resources` constructors
+ // mod_app_software_tasks -- free queues, buffers and `${task}Resources` constructors
Vec<TokenStream2>,
// root_software_tasks -- items that must be placed in the root of the crate:
// - `${task}Locals` structs
@@ -22,14 +22,15 @@ pub fn codegen(
Vec<TokenStream2>,
// user_software_tasks -- the `#[task]` functions written by the user
Vec<TokenStream2>,
+ // user_software_tasks_imports -- the imports for `#[task]` functions written by the user
+ Vec<TokenStream2>,
) {
- let mut const_app = vec![];
+ let mut mod_app = vec![];
let mut root = vec![];
let mut user_tasks = vec![];
+ let mut software_tasks_imports = vec![];
for (name, task) in &app.software_tasks {
- let receiver = task.args.core;
-
let inputs = &task.inputs;
let (_, _, _, input_ty) = util::regroup_inputs(inputs);
@@ -37,103 +38,70 @@ pub fn codegen(
let cap_lit = util::capacity_literal(cap);
let cap_ty = util::capacity_typenum(cap, true);
- // create free queues and inputs / instants buffers
- if let Some(free_queues) = analysis.free_queues.get(name) {
- for (&sender, &ceiling) in free_queues {
- let cfg_sender = util::cfg_core(sender, app.args.cores);
- let fq = util::fq_ident(name, sender);
-
- let (loc, fq_ty, fq_expr, bss, mk_uninit): (
- _,
- _,
- _,
- _,
- Box<dyn Fn() -> Option<_>>,
- ) = if receiver == sender {
- (
- cfg_sender.clone(),
- quote!(rtic::export::SCFQ<#cap_ty>),
- quote!(rtic::export::Queue(unsafe {
- rtic::export::iQueue::u8_sc()
- })),
- util::link_section("bss", sender),
- Box::new(|| util::link_section_uninit(Some(sender))),
- )
- } else {
- let shared = if cfg!(feature = "heterogeneous") {
- Some(quote!(#[rtic::export::shared]))
- } else {
- None
- };
-
- (
- shared,
- quote!(rtic::export::MCFQ<#cap_ty>),
- quote!(rtic::export::Queue(rtic::export::iQueue::u8())),
- None,
- Box::new(|| util::link_section_uninit(None)),
- )
- };
- let loc = &loc;
-
- const_app.push(quote!(
- /// Queue version of a free-list that keeps track of empty slots in
- /// the following buffers
- #loc
- #bss
- static mut #fq: #fq_ty = #fq_expr;
+ // Create free queues and inputs / instants buffers
+ if let Some(&ceiling) = analysis.free_queues.get(name) {
+ let fq = util::fq_ident(name);
+
+ let (fq_ty, fq_expr, mk_uninit): (_, _, Box<dyn Fn() -> Option<_>>) = {
+ (
+ quote!(rtic::export::SCFQ<#cap_ty>),
+ quote!(rtic::export::Queue(unsafe {
+ rtic::export::iQueue::u8_sc()
+ })),
+ Box::new(|| util::link_section_uninit(true)),
+ )
+ };
+ mod_app.push(quote!(
+ /// Queue version of a free-list that keeps track of empty slots in
+ /// the following buffers
+ static mut #fq: #fq_ty = #fq_expr;
+ ));
+
+ // Generate a resource proxy if needed
+ if let Some(ceiling) = ceiling {
+ mod_app.push(quote!(
+ struct #fq<'a> {
+ priority: &'a rtic::export::Priority,
+ }
+ ));
+
+ mod_app.push(util::impl_mutex(
+ extra,
+ &[],
+ false,
+ &fq,
+ fq_ty,
+ ceiling,
+ quote!(&mut #fq),
));
+ }
+
+ let ref elems = (0..cap)
+ .map(|_| quote!(core::mem::MaybeUninit::uninit()))
+ .collect::<Vec<_>>();
- // Generate a resource proxy if needed
- if let Some(ceiling) = ceiling {
- const_app.push(quote!(
- #cfg_sender
- struct #fq<'a> {
- priority: &'a rtic::export::Priority,
- }
- ));
-
- const_app.push(util::impl_mutex(
- extra,
- &[],
- cfg_sender.as_ref(),
- false,
- &fq,
- fq_ty,
- ceiling,
- quote!(&mut #fq),
- ));
- }
-
- let ref elems = (0..cap)
- .map(|_| quote!(core::mem::MaybeUninit::uninit()))
- .collect::<Vec<_>>();
-
- if app.uses_schedule(receiver) {
- let m = extra.monotonic();
- let instants = util::instants_ident(name, sender);
-
- let uninit = mk_uninit();
- const_app.push(quote!(
- #loc
- #uninit
- /// Buffer that holds the instants associated to the inputs of a task
- static mut #instants:
- [core::mem::MaybeUninit<<#m as rtic::Monotonic>::Instant>; #cap_lit] =
- [#(#elems,)*];
- ));
- }
+ if app.uses_schedule() {
+ let m = extra.monotonic();
+ let instants = util::instants_ident(name);
let uninit = mk_uninit();
- let inputs = util::inputs_ident(name, sender);
- const_app.push(quote!(
- #loc
+ mod_app.push(quote!(
#uninit
- /// Buffer that holds the inputs of a task
- static mut #inputs: [core::mem::MaybeUninit<#input_ty>; #cap_lit] =
+ /// Buffer that holds the instants associated to the inputs of a task
+ static mut #instants:
+ [core::mem::MaybeUninit<<#m as rtic::Monotonic>::Instant>; #cap_lit] =
[#(#elems,)*];
));
}
+
+ let uninit = mk_uninit();
+ let inputs = util::inputs_ident(name);
+ mod_app.push(quote!(
+ #uninit
+ /// Buffer that holds the inputs of a task
+ static mut #inputs: [core::mem::MaybeUninit<#input_ty>; #cap_lit] =
+ [#(#elems,)*];
+ ));
}
// `${task}Resources`
@@ -147,23 +115,27 @@ pub fn codegen(
analysis,
);
+ // Add resources to imports
+ let name_res = format_ident!("{}Resources", name);
+ software_tasks_imports.push(quote!(
+ #[allow(non_snake_case)]
+ use super::#name_res;
+ ));
+
root.push(item);
- const_app.push(constructor);
+ mod_app.push(constructor);
}
// `${task}Locals`
let mut locals_pat = None;
if !task.locals.is_empty() {
- let (struct_, pat) =
- locals::codegen(Context::SoftwareTask(name), &task.locals, receiver, app);
+ let (struct_, pat) = locals::codegen(Context::SoftwareTask(name), &task.locals, app);
locals_pat = Some(pat);
root.push(struct_);
}
- let cfg_receiver = util::cfg_core(receiver, app.args.cores);
- let section = util::link_section("text", receiver);
let context = &task.context;
let attrs = &task.attrs;
let cfgs = &task.cfgs;
@@ -173,14 +145,17 @@ pub fn codegen(
#(#attrs)*
#(#cfgs)*
#[allow(non_snake_case)]
- #cfg_receiver
- #section
- fn #name(#(#locals_pat,)* #context: #name::Context #(,#inputs)*) {
+ pub fn #name(#(#locals_pat,)* #context: #name::Context #(,#inputs)*) {
use rtic::Mutex as _;
#(#stmts)*
}
));
+ software_tasks_imports.push(quote!(
+ #(#cfgs)*
+ #[allow(non_snake_case)]
+ use super::#name;
+ ));
root.push(module::codegen(
Context::SoftwareTask(name),
@@ -190,5 +165,5 @@ pub fn codegen(
));
}
- (const_app, root, user_tasks)
+ (mod_app, root, user_tasks, software_tasks_imports)
}
diff --git a/macros/src/codegen/spawn.rs b/macros/src/codegen/spawn.rs
index 287c92a1..da281516 100644
--- a/macros/src/codegen/spawn.rs
+++ b/macros/src/codegen/spawn.rs
@@ -1,4 +1,4 @@
-use std::collections::{BTreeMap, HashSet};
+use std::collections::HashSet;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
@@ -14,16 +14,12 @@ use crate::{
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
let mut items = vec![];
- let mut seen = BTreeMap::<u8, HashSet<_>>::new();
+ let mut seen = HashSet::<_>::new();
for (spawner, spawnees) in app.spawn_callers() {
- let sender = spawner.core(app);
- let cfg_sender = util::cfg_core(sender, app.args.cores);
- let seen = seen.entry(sender).or_default();
let mut methods = vec![];
for name in spawnees {
let spawnee = &app.software_tasks[name];
- let receiver = spawnee.args.core;
let cfgs = &spawnee.cfgs;
let (args, _, untupled, ty) = util::regroup_inputs(&spawnee.inputs);
let args = &args;
@@ -34,7 +30,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let body = spawn_body::codegen(spawner, &name, app, analysis, extra);
- let let_instant = if app.uses_schedule(receiver) {
+ let let_instant = if app.uses_schedule() {
let m = extra.monotonic();
Some(quote!(let instant = unsafe { <#m as rtic::Monotonic>::zero() };))
@@ -42,23 +38,21 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
None
};
- let section = util::link_section("text", sender);
methods.push(quote!(
#(#cfgs)*
- #section
- fn #name(&self #(,#args)*) -> Result<(), #ty> {
+ pub fn #name(&self #(,#args)*) -> Result<(), #ty> {
#let_instant
#body
}
));
} else {
- let spawn = util::spawn_ident(name, sender);
+ let spawn = util::spawn_ident(name);
if !seen.contains(name) {
- // generate a `spawn_${name}_S${sender}` function
+ // Generate a `spawn_${name}_S${sender}` function
seen.insert(name);
- let instant = if app.uses_schedule(receiver) {
+ let instant = if app.uses_schedule() {
let m = extra.monotonic();
Some(quote!(, instant: <#m as rtic::Monotonic>::Instant))
@@ -68,11 +62,8 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let body = spawn_body::codegen(spawner, &name, app, analysis, extra);
- let section = util::link_section("text", sender);
items.push(quote!(
- #cfg_sender
#(#cfgs)*
- #section
unsafe fn #spawn(
priority: &rtic::export::Priority
#instant
@@ -83,7 +74,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
));
}
- let (let_instant, instant) = if app.uses_schedule(receiver) {
+ let (let_instant, instant) = if app.uses_schedule() {
let m = extra.monotonic();
(
@@ -101,7 +92,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
methods.push(quote!(
#(#cfgs)*
#[inline(always)]
- fn #name(&self #(,#args)*) -> Result<(), #ty> {
+ pub fn #name(&self #(,#args)*) -> Result<(), #ty> {
unsafe {
#let_instant
#spawn(self.priority() #instant #(,#untupled)*)
@@ -120,7 +111,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let spawner = spawner.ident(app);
debug_assert!(!methods.is_empty());
items.push(quote!(
- #cfg_sender
impl<#lt> #spawner::Spawn<#lt> {
#(#methods)*
}
diff --git a/macros/src/codegen/spawn_body.rs b/macros/src/codegen/spawn_body.rs
index 3433875e..4ecd0757 100644
--- a/macros/src/codegen/spawn_body.rs
+++ b/macros/src/codegen/spawn_body.rs
@@ -12,13 +12,11 @@ pub fn codegen(
analysis: &Analysis,
extra: &Extra,
) -> TokenStream2 {
- let sender = spawner.core(app);
let spawnee = &app.software_tasks[name];
let priority = spawnee.args.priority;
- let receiver = spawnee.args.core;
- let write_instant = if app.uses_schedule(receiver) {
- let instants = util::instants_ident(name, sender);
+ let write_instant = if app.uses_schedule() {
+ let instants = util::instants_ident(name);
Some(quote!(
#instants.get_unchecked_mut(usize::from(index)).as_mut_ptr().write(instant);
@@ -27,9 +25,9 @@ pub fn codegen(
None
};
- let t = util::spawn_t_ident(receiver, priority, sender);
- let fq = util::fq_ident(name, sender);
- let rq = util::rq_ident(receiver, priority, sender);
+ let t = util::spawn_t_ident(priority);
+ let fq = util::fq_ident(name);
+ let rq = util::rq_ident(priority);
let (dequeue, enqueue) = if spawner.is_init() {
(
quote!(#fq.dequeue()),
@@ -45,20 +43,16 @@ pub fn codegen(
};
let device = extra.device;
- let enum_ = util::interrupt_ident(receiver, app.args.cores);
- let interrupt = &analysis.interrupts[&receiver][&priority];
- let pend = if sender != receiver {
- quote!(
- #device::xpend(#receiver, #device::#enum_::#interrupt);
- )
- } else {
+ let enum_ = util::interrupt_ident();
+ let interrupt = &analysis.interrupts.get(&priority);
+ let pend = {
quote!(
rtic::pend(#device::#enum_::#interrupt);
)
};
let (_, tupled, _, _) = util::regroup_inputs(&spawnee.inputs);
- let inputs = util::inputs_ident(name, sender);
+ let inputs = util::inputs_ident(name);
quote!(
unsafe {
use rtic::Mutex as _;
diff --git a/macros/src/codegen/timer_queue.rs b/macros/src/codegen/timer_queue.rs
index 56304001..030158e2 100644
--- a/macros/src/codegen/timer_queue.rs
+++ b/macros/src/codegen/timer_queue.rs
@@ -8,9 +8,8 @@ use crate::{analyze::Analysis, check::Extra, codegen::util};
pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream2> {
let mut items = vec![];
- for (&sender, timer_queue) in &analysis.timer_queues {
- let cfg_sender = util::cfg_core(sender, app.args.cores);
- let t = util::schedule_t_ident(sender);
+ if let Some(timer_queue) = &analysis.timer_queues.first() {
+ let t = util::schedule_t_ident();
// Enumeration of `schedule`-able tasks
{
@@ -27,9 +26,8 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
})
.collect::<Vec<_>>();
- let doc = format!("Tasks that can be scheduled from core #{}", sender);
+ let doc = format!("Tasks that can be scheduled");
items.push(quote!(
- #cfg_sender
#[doc = #doc]
#[allow(non_camel_case_types)]
#[derive(Clone, Copy)]
@@ -39,27 +37,23 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
));
}
- let tq = util::tq_ident(sender);
+ let tq = util::tq_ident();
// Static variable and resource proxy
{
- let doc = format!("Core #{} timer queue", sender);
+ let doc = format!("Timer queue");
let m = extra.monotonic();
let n = util::capacity_typenum(timer_queue.capacity, false);
let tq_ty = quote!(rtic::export::TimerQueue<#m, #t, #n>);
- let section = util::link_section("bss", sender);
items.push(quote!(
- #cfg_sender
#[doc = #doc]
- #section
static mut #tq: #tq_ty = rtic::export::TimerQueue(
rtic::export::BinaryHeap(
rtic::export::iBinaryHeap::new()
)
);
- #cfg_sender
struct #tq<'a> {
priority: &'a rtic::export::Priority,
}
@@ -68,7 +62,6 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
items.push(util::impl_mutex(
extra,
&[],
- cfg_sender.as_ref(),
false,
&tq,
tq_ty,
@@ -88,17 +81,12 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
let cfgs = &task.cfgs;
let priority = task.args.priority;
- let receiver = task.args.core;
- let rq = util::rq_ident(receiver, priority, sender);
- let rqt = util::spawn_t_ident(receiver, priority, sender);
- let enum_ = util::interrupt_ident(receiver, app.args.cores);
- let interrupt = &analysis.interrupts[&receiver][&priority];
+ let rq = util::rq_ident(priority);
+ let rqt = util::spawn_t_ident(priority);
+ let enum_ = util::interrupt_ident();
+ let interrupt = &analysis.interrupts.get(&priority);
- let pend = if sender != receiver {
- quote!(
- #device::xpend(#receiver, #device::#enum_::#interrupt);
- )
- } else {
+ let pend = {
quote!(
rtic::pend(#device::#enum_::#interrupt);
)
@@ -118,12 +106,9 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
.collect::<Vec<_>>();
let priority = timer_queue.priority;
- let sys_tick = util::suffixed("SysTick", sender);
- let section = util::link_section("text", sender);
+ let sys_tick = util::suffixed("SysTick");
items.push(quote!(
#[no_mangle]
- #cfg_sender
- #section
unsafe fn #sys_tick() {
use rtic::Mutex as _;
@@ -137,7 +122,7 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
})
// NOTE `inline(always)` produces faster and smaller code
.lock(#[inline(always)]
- |tq| tq.dequeue())
+ |tq| tq.dequeue())
{
match task {
#(#arms)*
@@ -148,6 +133,5 @@ pub fn codegen(app: &App, analysis: &Analysis, extra: &Extra) -> Vec<TokenStream
));
}
}
-
items
}
diff --git a/macros/src/codegen/util.rs b/macros/src/codegen/util.rs
index 68aca5d1..2f9f3cce 100644
--- a/macros/src/codegen/util.rs
+++ b/macros/src/codegen/util.rs
@@ -2,7 +2,7 @@ use core::sync::atomic::{AtomicUsize, Ordering};
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::quote;
-use rtic_syntax::{ast::App, Context, Core};
+use rtic_syntax::{ast::App, Context};
use syn::{Attribute, Ident, LitInt, PatType};
use crate::check::Extra;
@@ -25,34 +25,15 @@ pub fn capacity_typenum(capacity: u8, round_up_to_power_of_two: bool) -> TokenSt
quote!(rtic::export::consts::#ident)
}
-/// Generates a `#[cfg(core = "0")]` attribute if we are in multi-core mode
-pub fn cfg_core(core: Core, cores: u8) -> Option<TokenStream2> {
- if cores == 1 {
- None
- } else if cfg!(feature = "heterogeneous") {
- let core = core.to_string();
- Some(quote!(#[cfg(core = #core)]))
- } else {
- None
- }
-}
-
/// Identifier for the free queue
-///
-/// There may be more than one free queue per task because we need one for each sender core so we
-/// include the sender (e.g. `S0`) in the name
-pub fn fq_ident(task: &Ident, sender: Core) -> Ident {
- Ident::new(
- &format!("{}_S{}_FQ", task.to_string(), sender),
- Span::call_site(),
- )
+pub fn fq_ident(task: &Ident) -> Ident {
+ Ident::new(&format!("{}_FQ", task.to_string()), Span::call_site())
}
/// Generates a `Mutex` implementation
pub fn impl_mutex(
extra: &Extra,
cfgs: &[Attribute],
- cfg_core: Option<&TokenStream2>,
resources_prefix: bool,
name: &Ident,
ty: TokenStream2,
@@ -68,7 +49,6 @@ pub fn impl_mutex(
let device = extra.device;
quote!(
#(#cfgs)*
- #cfg_core
impl<'a> rtic::Mutex for #path<'a> {
type T = #ty;
@@ -91,28 +71,19 @@ pub fn impl_mutex(
)
}
-/// Generates an identifier for a cross-initialization barrier
-pub fn init_barrier(initializer: Core) -> Ident {
- Ident::new(&format!("IB{}", initializer), Span::call_site())
-}
-
/// Generates an identifier for the `INPUTS` buffer (`spawn` & `schedule` API)
-pub fn inputs_ident(task: &Ident, sender: Core) -> Ident {
- Ident::new(&format!("{}_S{}_INPUTS", task, sender), Span::call_site())
+pub fn inputs_ident(task: &Ident) -> Ident {
+ Ident::new(&format!("{}_INPUTS", task), Span::call_site())
}
/// Generates an identifier for the `INSTANTS` buffer (`schedule` API)
-pub fn instants_ident(task: &Ident, sender: Core) -> Ident {
- Ident::new(&format!("{}_S{}_INSTANTS", task, sender), Span::call_site())
+pub fn instants_ident(task: &Ident) -> Ident {
+ Ident::new(&format!("{}_INSTANTS", task), Span::call_site())
}
-pub fn interrupt_ident(core: Core, cores: u8) -> Ident {
+pub fn interrupt_ident() -> Ident {
let span = Span::call_site();
- if cores == 1 {
- Ident::new("Interrupt", span)
- } else {
- Ident::new(&format!("Interrupt_{}", core), span)
- }
+ Ident::new("Interrupt", span)
}
/// Whether `name` is an exception with configurable priority
@@ -141,31 +112,12 @@ fn link_section_index() -> usize {
INDEX.fetch_add(1, Ordering::Relaxed)
}
-pub fn link_section(section: &str, core: Core) -> Option<TokenStream2> {
- if cfg!(feature = "homogeneous") {
- let section = format!(".{}_{}.rtic{}", section, core, link_section_index());
- Some(quote!(#[link_section = #section]))
- } else {
- None
- }
-}
-
// NOTE `None` means in shared memory
-pub fn link_section_uninit(core: Option<Core>) -> Option<TokenStream2> {
- let section = if let Some(core) = core {
+pub fn link_section_uninit(empty_expr: bool) -> Option<TokenStream2> {
+ let section = if empty_expr {
let index = link_section_index();
-
- if cfg!(feature = "homogeneous") {
- format!(".uninit_{}.rtic{}", core, index)
- } else {
- format!(".uninit.rtic{}", index)
- }
+ format!(".uninit.rtic{}", index)
} else {
- if cfg!(feature = "heterogeneous") {
- // `#[shared]` attribute sets the linker section
- return None;
- }
-
format!(".uninit.rtic{}", link_section_index())
};
@@ -175,8 +127,8 @@ pub fn link_section_uninit(core: Option<Core>) -> Option<TokenStream2> {
/// Generates a pre-reexport identifier for the "locals" struct
pub fn locals_ident(ctxt: Context, app: &App) -> Ident {
let mut s = match ctxt {
- Context::Init(core) => app.inits[&core].name.to_string(),
- Context::Idle(core) => app.idles[&core].name.to_string(),
+ Context::Init => app.inits.first().unwrap().name.to_string(),
+ Context::Idle => app.idles.first().unwrap().name.to_string(),
Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(),
};
@@ -185,11 +137,6 @@ pub fn locals_ident(ctxt: Context, app: &App) -> Ident {
Ident::new(&s, Span::call_site())
}
-/// Generates an identifier for a rendezvous barrier
-pub fn rendezvous_ident(core: Core) -> Ident {
- Ident::new(&format!("RV{}", core), Span::call_site())
-}
-
// Regroups the inputs of a task
//
// `inputs` could be &[`input: Foo`] OR &[`mut x: i32`, `ref y: i64`]
@@ -242,8 +189,8 @@ pub fn regroup_inputs(
/// Generates a pre-reexport identifier for the "resources" struct
pub fn resources_ident(ctxt: Context, app: &App) -> Ident {
let mut s = match ctxt {
- Context::Init(core) => app.inits[&core].name.to_string(),
- Context::Idle(core) => app.idles[&core].name.to_string(),
+ Context::Init => app.inits.first().unwrap().name.to_string(),
+ Context::Idle => app.idles.first().unwrap().name.to_string(),
Context::HardwareTask(ident) | Context::SoftwareTask(ident) => ident.to_string(),
};
@@ -254,72 +201,47 @@ pub fn resources_ident(ctxt: Context, app: &App) -> Ident {
/// Generates an identifier for a ready queue
///
-/// Each core may have several task dispatchers, one for each priority level. Each task dispatcher
-/// in turn may use more than one ready queue because the queues are SPSC queues so one is needed
-/// per sender core.
-pub fn rq_ident(receiver: Core, priority: u8, sender: Core) -> Ident {
- Ident::new(
- &format!("R{}_P{}_S{}_RQ", receiver, priority, sender),
- Span::call_site(),
- )
+/// There may be several task dispatchers, one for each priority level.
+/// The ready queues are SPSC queues
+pub fn rq_ident(priority: u8) -> Ident {
+ Ident::new(&format!("P{}_RQ", priority), Span::call_site())
}
/// Generates an identifier for a "schedule" function
///
-/// The methods of the `Schedule` structs invoke these functions. As one task may be `schedule`-ed
-/// by different cores we need one "schedule" function per possible task-sender pair
-pub fn schedule_ident(name: &Ident, sender: Core) -> Ident {
- Ident::new(
- &format!("schedule_{}_S{}", name.to_string(), sender),
- Span::call_site(),
- )
+/// The methods of the `Schedule` structs invoke these functions.
+pub fn schedule_ident(name: &Ident) -> Ident {
+ Ident::new(&format!("schedule_{}", name.to_string()), Span::call_site())
}
/// Generates an identifier for the `enum` of `schedule`-able tasks
-pub fn schedule_t_ident(core: Core) -> Ident {
- Ident::new(&format!("T{}", core), Span::call_site())
-}
-
-/// Generates an identifier for a cross-spawn barrier
-pub fn spawn_barrier(receiver: Core) -> Ident {
- Ident::new(&format!("SB{}", receiver), Span::call_site())
+pub fn schedule_t_ident() -> Ident {
+ Ident::new(&format!("T"), Span::call_site())
}
/// Generates an identifier for a "spawn" function
///
-/// The methods of the `Spawn` structs invoke these functions. As one task may be `spawn`-ed by
-/// different cores we need one "spawn" function per possible task-sender pair
-pub fn spawn_ident(name: &Ident, sender: Core) -> Ident {
- Ident::new(
- &format!("spawn_{}_S{}", name.to_string(), sender),
- Span::call_site(),
- )
+/// The methods of the `Spawn` structs invoke these functions.
+pub fn spawn_ident(name: &Ident) -> Ident {
+ Ident::new(&format!("spawn_{}", name.to_string()), Span::call_site())
}
/// Generates an identifier for the `enum` of `spawn`-able tasks
///
/// This identifier needs the same structure as the `RQ` identifier because there's one ready queue
/// for each of these `T` enums
-pub fn spawn_t_ident(receiver: Core, priority: u8, sender: Core) -> Ident {
- Ident::new(
- &format!("R{}_P{}_S{}_T", receiver, priority, sender),
- Span::call_site(),
- )
+pub fn spawn_t_ident(priority: u8) -> Ident {
+ Ident::new(&format!("P{}_T", priority), Span::call_site())
}
-pub fn suffixed(name: &str, core: u8) -> Ident {
+pub fn suffixed(name: &str) -> Ident {
let span = Span::call_site();
-
- if cfg!(feature = "homogeneous") {
- Ident::new(&format!("{}_{}", name, core), span)
- } else {
- Ident::new(name, span)
- }
+ Ident::new(name, span)
}
/// Generates an identifier for a timer queue
///
-/// At most there's one timer queue per core
-pub fn tq_ident(core: Core) -> Ident {
- Ident::new(&format!("TQ{}", core), Span::call_site())
+/// At most there is one timer queue
+pub fn tq_ident() -> Ident {
+ Ident::new(&format!("TQ"), Span::call_site())
}
diff --git a/macros/src/lib.rs b/macros/src/lib.rs
index b5803628..e659559e 100644
--- a/macros/src/lib.rs
+++ b/macros/src/lib.rs
@@ -15,8 +15,7 @@ mod tests;
/// Attribute used to declare a RTIC application
///
-/// This attribute must be applied to a `const` item of type `()`. The `const` item is effectively
-/// used as a `mod` item: its value must be a block that contains items commonly found in modules,
+/// This attribute must be applied to a module block that contains items commonly found in modules,
/// like functions and `static` variables.
///
/// The `app` attribute has one mandatory argument:
@@ -34,9 +33,9 @@ mod tests;
/// - `monotonic = <path>`. This is a path to a zero-sized structure (e.g. `struct Foo;`) that
/// implements the `Monotonic` trait. This argument must be provided to use the `schedule` API.
///
-/// The items allowed in the block value of the `const` item are specified below:
+/// The items allowed in the module block are specified below:
///
-/// # 1. `struct Resources`
+/// # 1. `#[resources] struct <resource-name>`
///
/// This structure contains the declaration of all the resources used by the application. Each field
/// in this structure corresponds to a different resource. Each resource may optionally be given an
@@ -201,12 +200,12 @@ mod tests;
///
/// Attributes can be applied to the functions inside this block. These attributes will be forwarded
/// to the interrupt handlers generated by the `app` attribute.
+
#[proc_macro_attribute]
pub fn app(args: TokenStream, input: TokenStream) -> TokenStream {
let mut settings = Settings::default();
settings.optimize_priorities = true;
settings.parse_binds = true;
- settings.parse_cores = cfg!(feature = "heterogeneous") || cfg!(feature = "homogeneous");
settings.parse_extern_interrupt = true;
settings.parse_schedule = true;
diff --git a/macros/src/tests.rs b/macros/src/tests.rs
index 94969d1a..e9e3326e 100644
--- a/macros/src/tests.rs
+++ b/macros/src/tests.rs
@@ -1,5 +1,4 @@
// NOTE these tests are specific to the Cortex-M port; `rtic-syntax` has a more extensive test suite
// that tests functionality common to all the RTIC ports
-mod multi;
mod single;
diff --git a/macros/src/tests/multi.rs b/macros/src/tests/multi.rs
deleted file mode 100644
index 366789be..00000000
--- a/macros/src/tests/multi.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-use quote::quote;
-use rtic_syntax::Settings;
-
-#[test]
-fn analyze() {
- let mut settings = Settings::default();
- settings.parse_cores = true;
- settings.parse_extern_interrupt = true;
-
- let (app, analysis) = rtic_syntax::parse2(
- quote!(device = pac, cores = 2),
- quote!(
- const APP: () = {
- #[task(core = 0, priority = 1)]
- fn a(_: a::Context) {}
-
- #[task(core = 0, priority = 2)]
- fn b(_: b::Context) {}
-
- #[task(core = 1, priority = 1)]
- fn c(_: c::Context) {}
-
- #[task(core = 1, priority = 2)]
- fn d(_: d::Context) {}
-
- // first interrupt is assigned to the highest priority dispatcher
- extern "C" {
- #[core = 0]
- fn B();
-
- #[core = 0]
- fn A();
-
- #[core = 1]
- fn A();
-
- #[core = 1]
- fn C();
- }
- };
- ),
- settings,
- )
- .unwrap();
-
- let analysis = crate::analyze::app(analysis, &app);
-
- // first core
- let interrupts0 = &analysis.interrupts[&0];
- assert_eq!(interrupts0.len(), 2);
- assert_eq!(interrupts0[&2].to_string(), "B");
- assert_eq!(interrupts0[&1].to_string(), "A");
-
- // second core
- let interrupts1 = &analysis.interrupts[&1];
- assert_eq!(interrupts1.len(), 2);
- assert_eq!(interrupts1[&2].to_string(), "A");
- assert_eq!(interrupts1[&1].to_string(), "C");
-}
diff --git a/macros/src/tests/single.rs b/macros/src/tests/single.rs
index 497d1da7..97cbbb3f 100644
--- a/macros/src/tests/single.rs
+++ b/macros/src/tests/single.rs
@@ -8,26 +8,26 @@ fn analyze() {
let (app, analysis) = rtic_syntax::parse2(
quote!(device = pac),
quote!(
- const APP: () = {
+ mod app {
#[task(priority = 1)]
fn a(_: a::Context) {}
#[task(priority = 2)]
fn b(_: b::Context) {}
- // first interrupt is assigned to the highest priority dispatcher
+ // First interrupt is assigned to the highest priority dispatcher
extern "C" {
fn B();
fn A();
}
- };
+ }
),
settings,
)
.unwrap();
let analysis = crate::analyze::app(analysis, &app);
- let interrupts = &analysis.interrupts[&0];
+ let interrupts = &analysis.interrupts;
assert_eq!(interrupts.len(), 2);
assert_eq!(interrupts[&2].to_string(), "B");
assert_eq!(interrupts[&1].to_string(), "A");
diff --git a/src/cyccnt.rs b/src/cyccnt.rs
index 6bc2ef0a..8e07b001 100644
--- a/src/cyccnt.rs
+++ b/src/cyccnt.rs
@@ -19,10 +19,6 @@ use crate::Fraction;
/// Adding or subtracting a `Duration` of more than `(1 << 31)` cycles to an `Instant` effectively
/// makes it "wrap around" and creates an incorrect value. This is also true if the operation is
/// done in steps, e.g. `(instant + dur) + dur` where `dur` is `(1 << 30)` ticks.
-///
-/// In multi-core contexts: this value is tied to the CYCCNT of *one* core so sending it a different
-/// core makes it lose its meaning -- each Cortex-M core has its own CYCCNT counter and these are
-/// usually unsynchronized and may even be running at different frequencies.
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Instant {
inner: i32,
diff --git a/src/export.rs b/src/export.rs
index e23b8f3a..27f7f5fb 100644
--- a/src/export.rs
+++ b/src/export.rs
@@ -4,6 +4,7 @@ use core::{
};
pub use crate::tq::{NotReady, TimerQueue};
+pub use bare_metal::CriticalSection;
#[cfg(armv7m)]
pub use cortex_m::register::basepri;
pub use cortex_m::{
@@ -12,14 +13,10 @@ pub use cortex_m::{
peripheral::{scb::SystemHandler, syst::SystClkSource, DWT, NVIC},
Peripherals,
};
-use heapless::spsc::{MultiCore, SingleCore};
+use heapless::spsc::SingleCore;
pub use heapless::{consts, i::Queue as iQueue, spsc::Queue};
pub use heapless::{i::BinaryHeap as iBinaryHeap, BinaryHeap};
-#[cfg(feature = "heterogeneous")]
-pub use microamp::shared;
-pub type MCFQ<N> = Queue<u8, N, u8, MultiCore>;
-pub type MCRQ<T, N> = Queue<(T, u8), N, u8, MultiCore>;
pub type SCFQ<N> = Queue<u8, N, u8, SingleCore>;
pub type SCRQ<T, N> = Queue<(T, u8), N, u8, SingleCore>;
@@ -30,7 +27,7 @@ where
F: FnOnce(),
{
if priority == 1 {
- // if the priority of this interrupt is `1` then BASEPRI can only be `0`
+ // If the priority of this interrupt is `1` then BASEPRI can only be `0`
f();
unsafe { basepri::write(0) }
} else {
@@ -82,7 +79,7 @@ impl Priority {
}
}
- // these two methods are used by `lock` (see below) but can't be used from the RTIC application
+ // These two methods are used by `lock` (see below) but can't be used from the RTIC application
#[inline(always)]
fn set(&self, value: u8) {
self.inner.set(value)
@@ -108,13 +105,6 @@ where
{
}
-#[inline(always)]
-pub fn assert_multicore<T>()
-where
- T: super::MultiCore,
-{
-}
-
#[cfg(armv7m)]
#[inline(always)]
pub unsafe fn lock<T, R>(
diff --git a/src/lib.rs b/src/lib.rs
index 50036531..a7d399cd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -28,13 +28,6 @@
//! release.
//!
//! [SemVer]: https://semver.org/spec/v2.0.0.html
-//!
-//! # Cargo features
-//!
-//! - `heterogeneous`. This opt-in feature enables the *experimental* heterogeneous multi-core
-//! support. This feature depends on unstable feature and requires the use of the nightly channel.
-//!
-//! - `homogeneous`. This opt-in feature enables the *experimental* homogeneous multi-core support.
#![deny(missing_docs)]
#![deny(rust_2018_compatibility)]
@@ -48,7 +41,6 @@ use cortex_m::{
interrupt::Nr,
peripheral::{CBP, CPUID, DCB, DWT, FPB, FPU, ITM, MPU, NVIC, SCB, TPIU},
};
-#[cfg(all(not(feature = "heterogeneous"), not(feature = "homogeneous")))]
use cortex_m_rt as _; // vector table
pub use cortex_m_rtic_macros::app;
pub use rtic_core::{Exclusive, Mutex};
@@ -161,9 +153,6 @@ pub trait Monotonic {
fn zero() -> Self::Instant;
}
-/// A marker trait that indicates that it is correct to use this type in multi-core context
-pub trait MultiCore {}
-
/// Sets the given `interrupt` as pending
///
/// This is a convenience function around
diff --git a/src/tq.rs b/src/tq.rs
index 21beeb9c..9300dbfc 100644
--- a/src/tq.rs
+++ b/src/tq.rs
@@ -40,7 +40,7 @@ where
mem::transmute::<_, SYST>(()).enable_interrupt();
}
- // set SysTick pending
+ // Set SysTick pending
SCB::set_pendst();
}
@@ -79,13 +79,13 @@ where
};
mem::transmute::<_, SYST>(()).set_reload(dur);
- // start counting down from the new reload
+ // Start counting down from the new reload
mem::transmute::<_, SYST>(()).clear_current();
None
}
} else {
- // the queue is empty
+ // The queue is empty
mem::transmute::<_, SYST>(()).disable_interrupt();
None
diff --git a/ui/single/exception-invalid.rs b/ui/single/exception-invalid.rs
index efe06212..04d9bc75 100644
--- a/ui/single/exception-invalid.rs
+++ b/ui/single/exception-invalid.rs
@@ -1,7 +1,7 @@
#![no_main]
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[task(binds = NonMaskableInt)]
fn nmi(_: nmi::Context) {}
-};
+}
diff --git a/ui/single/exception-systick-used.rs b/ui/single/exception-systick-used.rs
index 36ed1744..1c30b700 100644
--- a/ui/single/exception-systick-used.rs
+++ b/ui/single/exception-systick-used.rs
@@ -1,10 +1,10 @@
#![no_main]
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[task(binds = SysTick)]
fn sys_tick(_: sys_tick::Context) {}
#[task(schedule = [foo])]
fn foo(_: foo::Context) {}
-};
+}
diff --git a/ui/single/extern-interrupt-not-enough.rs b/ui/single/extern-interrupt-not-enough.rs
index 53820b52..f2624036 100644
--- a/ui/single/extern-interrupt-not-enough.rs
+++ b/ui/single/extern-interrupt-not-enough.rs
@@ -1,7 +1,7 @@
#![no_main]
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[task]
fn a(_: a::Context) {}
-};
+}
diff --git a/ui/single/extern-interrupt-used.rs b/ui/single/extern-interrupt-used.rs
index 82f1bdd2..89c23784 100644
--- a/ui/single/extern-interrupt-used.rs
+++ b/ui/single/extern-interrupt-used.rs
@@ -1,11 +1,11 @@
#![no_main]
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[task(binds = UART0)]
fn a(_: a::Context) {}
extern "C" {
fn UART0();
}
-};
+}
diff --git a/ui/single/locals-cfg.rs b/ui/single/locals-cfg.rs
index 54bba8ae..45a7a911 100644
--- a/ui/single/locals-cfg.rs
+++ b/ui/single/locals-cfg.rs
@@ -1,13 +1,16 @@
#![no_main]
+use panic_halt as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn init(_: init::Context) {
+ fn init(_: init::Context) -> init::LateResources {
#[cfg(never)]
static mut FOO: u32 = 0;
FOO;
+
+ init::LateResources {}
}
#[idle]
@@ -47,4 +50,4 @@ const APP: () = {
extern "C" {
fn UART1();
}
-};
+}
diff --git a/ui/single/locals-cfg.stderr b/ui/single/locals-cfg.stderr
index bb558fa6..e58bd935 100644
--- a/ui/single/locals-cfg.stderr
+++ b/ui/single/locals-cfg.stderr
@@ -1,37 +1,41 @@
error[E0425]: cannot find value `FOO` in this scope
- --> $DIR/locals-cfg.rs:10:9
+ --> $DIR/locals-cfg.rs:11:9
|
-10 | FOO;
+11 | FOO;
| ^^^ not found in this scope
error[E0425]: cannot find value `FOO` in this scope
- --> $DIR/locals-cfg.rs:18:9
+ --> $DIR/locals-cfg.rs:21:9
|
-18 | FOO;
+21 | FOO;
| ^^^ not found in this scope
error[E0425]: cannot find value `FOO` in this scope
- --> $DIR/locals-cfg.rs:28:9
+ --> $DIR/locals-cfg.rs:31:9
|
-28 | FOO;
+31 | FOO;
| ^^^ not found in this scope
error[E0425]: cannot find value `FOO` in this scope
- --> $DIR/locals-cfg.rs:36:9
+ --> $DIR/locals-cfg.rs:39:9
|
-36 | FOO;
+39 | FOO;
| ^^^ not found in this scope
error[E0425]: cannot find value `FOO` in this scope
- --> $DIR/locals-cfg.rs:44:9
+ --> $DIR/locals-cfg.rs:47:9
|
-44 | FOO;
+47 | FOO;
| ^^^ not found in this scope
-error: duplicate lang item in crate `panic_halt`: `panic_impl`.
+error: duplicate lang item in crate `panic_halt` (which `$CRATE` depends on): `panic_impl`.
|
- = note: first defined in crate `std`.
+ = note: the lang item is first defined in crate `std` (which `$CRATE` depends on)
+ = note: first definition in `std` loaded from /usr/share/rust/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-cf0f33af3a901778.rlib
+ = note: second definition in `panic_halt` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_halt-ba6f0ab3439cbc7e.rmeta
error: duplicate lang item in crate `panic_semihosting`: `panic_impl`.
|
- = note: first defined in crate `panic_halt`.
+ = note: the lang item is first defined in crate `panic_halt` (which `$CRATE` depends on)
+ = note: first definition in `panic_halt` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_halt-ba6f0ab3439cbc7e.rmeta
+ = note: second definition in `panic_semihosting` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_semihosting-805015f4a2d05965.rmeta
diff --git a/ui/single/resources-cfg.rs b/ui/single/resources-cfg.rs
index df7ac806..2ba65a04 100644
--- a/ui/single/resources-cfg.rs
+++ b/ui/single/resources-cfg.rs
@@ -1,7 +1,9 @@
#![no_main]
+use panic_halt as _;
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
+ #[resources]
struct Resources {
#[cfg(never)]
#[init(0)]
@@ -41,12 +43,14 @@ const APP: () = {
}
#[init(resources = [o1, o4, o5, o6, s3])]
- fn init(c: init::Context) {
+ fn init(c: init::Context) -> init::LateResources {
c.resources.o1;
c.resources.o4;
c.resources.o5;
c.resources.o6;
c.resources.s3;
+
+ init::LateResources {}
}
#[idle(resources = [o2, &o4, s1, &s3])]
@@ -72,4 +76,4 @@ const APP: () = {
c.resources.s2;
c.resources.o5;
}
-};
+}
diff --git a/ui/single/resources-cfg.stderr b/ui/single/resources-cfg.stderr
index c47b95d4..17f08d81 100644
--- a/ui/single/resources-cfg.stderr
+++ b/ui/single/resources-cfg.stderr
@@ -1,119 +1,125 @@
+error: duplicate lang item in crate `panic_halt` (which `$CRATE` depends on): `panic_impl`.
+ |
+ = note: the lang item is first defined in crate `std` (which `$CRATE` depends on)
+ = note: first definition in `std` loaded from /usr/share/rust/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-cf0f33af3a901778.rlib
+ = note: second definition in `panic_halt` loaded from $DIR/target/tests/target/x86_64-unknown-linux-gnu/debug/deps/libpanic_halt-ba6f0ab3439cbc7e.rmeta
+
error[E0609]: no field `o1` on type `initResources<'_>`
- --> $DIR/resources-cfg.rs:45:21
+ --> $DIR/resources-cfg.rs:47:21
|
-45 | c.resources.o1;
+47 | c.resources.o1;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `o4` on type `initResources<'_>`
- --> $DIR/resources-cfg.rs:46:21
+ --> $DIR/resources-cfg.rs:48:21
|
-46 | c.resources.o4;
+48 | c.resources.o4;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `o5` on type `initResources<'_>`
- --> $DIR/resources-cfg.rs:47:21
+ --> $DIR/resources-cfg.rs:49:21
|
-47 | c.resources.o5;
+49 | c.resources.o5;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `o6` on type `initResources<'_>`
- --> $DIR/resources-cfg.rs:48:21
+ --> $DIR/resources-cfg.rs:50:21
|
-48 | c.resources.o6;
+50 | c.resources.o6;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s3` on type `initResources<'_>`
- --> $DIR/resources-cfg.rs:49:21
+ --> $DIR/resources-cfg.rs:51:21
|
-49 | c.resources.s3;
+51 | c.resources.s3;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `o2` on type `idleResources<'_>`
- --> $DIR/resources-cfg.rs:54:21
+ --> $DIR/resources-cfg.rs:58:21
|
-54 | c.resources.o2;
+58 | c.resources.o2;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `o4` on type `idleResources<'_>`
- --> $DIR/resources-cfg.rs:55:21
+ --> $DIR/resources-cfg.rs:59:21
|
-55 | c.resources.o4;
+59 | c.resources.o4;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s1` on type `idleResources<'_>`
- --> $DIR/resources-cfg.rs:56:21
+ --> $DIR/resources-cfg.rs:60:21
|
-56 | c.resources.s1;
+60 | c.resources.s1;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s3` on type `idleResources<'_>`
- --> $DIR/resources-cfg.rs:57:21
+ --> $DIR/resources-cfg.rs:61:21
|
-57 | c.resources.s3;
+61 | c.resources.s3;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `o3` on type `uart0Resources<'_>`
- --> $DIR/resources-cfg.rs:64:21
+ --> $DIR/resources-cfg.rs:68:21
|
-64 | c.resources.o3;
+68 | c.resources.o3;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s1` on type `uart0Resources<'_>`
- --> $DIR/resources-cfg.rs:65:21
+ --> $DIR/resources-cfg.rs:69:21
|
-65 | c.resources.s1;
+69 | c.resources.s1;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s2` on type `uart0Resources<'_>`
- --> $DIR/resources-cfg.rs:66:21
+ --> $DIR/resources-cfg.rs:70:21
|
-66 | c.resources.s2;
+70 | c.resources.s2;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s3` on type `uart0Resources<'_>`
- --> $DIR/resources-cfg.rs:67:21
+ --> $DIR/resources-cfg.rs:71:21
|
-67 | c.resources.s3;
+71 | c.resources.s3;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `s2` on type `uart1Resources<'_>`
- --> $DIR/resources-cfg.rs:72:21
+ --> $DIR/resources-cfg.rs:76:21
|
-72 | c.resources.s2;
+76 | c.resources.s2;
| ^^ unknown field
|
= note: available fields are: `__marker__`
error[E0609]: no field `o5` on type `uart1Resources<'_>`
- --> $DIR/resources-cfg.rs:73:21
+ --> $DIR/resources-cfg.rs:77:21
|
-73 | c.resources.o5;
+77 | c.resources.o5;
| ^^ unknown field
|
= note: available fields are: `__marker__`
diff --git a/ui/single/task-priority-too-high.rs b/ui/single/task-priority-too-high.rs
index 539c3f5d..caa7b8ee 100644
--- a/ui/single/task-priority-too-high.rs
+++ b/ui/single/task-priority-too-high.rs
@@ -1,11 +1,11 @@
#![no_main]
-use rtic::app;
-
#[rtic::app(device = lm3s6965)]
-const APP: () = {
+mod app {
#[init]
- fn init(_: init::Context) {}
+ fn init(_: init::Context) -> init::LateResources {
+ init::LateResources {}
+ }
#[task(binds = GPIOA, priority = 1)]
fn gpioa(_: gpioa::Context) {}
@@ -35,4 +35,4 @@ const APP: () = {
// this value is too high!
#[task(binds = I2C0, priority = 9)]
fn i2c0(_: i2c0::Context) {}
-};
+}
diff --git a/ui/single/task-priority-too-high.stderr b/ui/single/task-priority-too-high.stderr
index eae6074d..e84ddd3c 100644
--- a/ui/single/task-priority-too-high.stderr
+++ b/ui/single/task-priority-too-high.stderr
@@ -1,13 +1,7 @@
-warning: unused import: `rtic::app`
- --> $DIR/task-priority-too-high.rs:3:5
- |
-3 | use rtic::app;
- | ^^^^^^^^^
- |
- = note: #[warn(unused_imports)] on by default
-
error[E0080]: evaluation of constant value failed
- --> $DIR/task-priority-too-high.rs:5:1
+ --> $DIR/task-priority-too-high.rs:3:1
+ |
+3 | #[rtic::app(device = lm3s6965)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `8_usize - 9_usize` which would overflow
|
-5 | #[rtic::app(device = lm3s6965)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to subtract with overflow
+ = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)