From 4060c3def88f82d4e4f48de7137ce365167ef265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rom=C3=A1n=20C=C3=A1rdenas=20Rodr=C3=ADguez?= Date: Wed, 20 Mar 2024 21:06:47 +0100 Subject: RISC-V support over CLINT (#815) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Rebase to master * using interrupt_mod * bug fixes * fix other backends * Add changelog * forgot about rtic-macros * backend-specific configuration * core peripherals optional over macro argument * pre_init_preprocessing binding * CI for RISC-V (WIP) * separation of concerns * add targets for RISC-V examples * remove qemu feature * prepare examples folder * move examples all together * move ci out of examples * minor changes * add cortex-m * new xtask: proof of concept * fix build.yml * feature typo * clean rtic examples * reproduce weird issue * remove unsafe code in user app * update dependencies * allow builds on riscv32imc * let's fix QEMU * Update .github/workflows/build.yml Co-authored-by: Henrik Tjäder * New build.rs * removing test features * adapt ui test to new version of clippy * add more examples to RISC-V backend * proper configuration of heapless for riscv32imc * opt-out examples for riscv32imc * point to new version of riscv-slic * adapt new macro bindings * adapt examples and CI to stable * fix cortex-m CI * Review --------- Co-authored-by: Henrik Tjäder --- .github/workflows/build.yml | 150 ++++-- .gitignore | 3 + ci/expected/hifive1/prio_inheritance.run | 17 + ci/expected/hifive1/static.run | 3 + ci/expected/hifive1/task.run | 5 + ci/expected/hifive1/zero_prio_task.run | 3 + ci/expected/lm3s6965/async-channel-done.run | 9 + ci/expected/lm3s6965/async-channel-no-receiver.run | 1 + ci/expected/lm3s6965/async-channel-no-sender.run | 1 + ci/expected/lm3s6965/async-channel-try.run | 2 + ci/expected/lm3s6965/async-channel.run | 6 + ci/expected/lm3s6965/async-delay.run | 7 + ci/expected/lm3s6965/async-infinite-loop.run | 6 + ci/expected/lm3s6965/async-task-multiple-prios.run | 6 + ci/expected/lm3s6965/async-task.run | 5 + ci/expected/lm3s6965/async-timeout.run | 16 + ci/expected/lm3s6965/big-struct-opt.run | 3 + ci/expected/lm3s6965/binds.run | 4 + ci/expected/lm3s6965/cancel-reschedule.run | 3 + ci/expected/lm3s6965/capacity.run | 5 + ci/expected/lm3s6965/cfg-whole-task.run | 0 ci/expected/lm3s6965/common.run | 3 + ci/expected/lm3s6965/complex.run | 47 ++ ci/expected/lm3s6965/declared_locals.run | 0 ci/expected/lm3s6965/destructure.run | 2 + ci/expected/lm3s6965/executor-size.run | 1 + ci/expected/lm3s6965/extern_binds.run | 4 + ci/expected/lm3s6965/extern_spawn.run | 1 + ci/expected/lm3s6965/generics.run | 6 + ci/expected/lm3s6965/hardware.run | 4 + ci/expected/lm3s6965/idle-wfi.run | 2 + ci/expected/lm3s6965/idle.run | 2 + ci/expected/lm3s6965/init.run | 1 + ci/expected/lm3s6965/locals.run | 3 + ci/expected/lm3s6965/lock-free.run | 2 + ci/expected/lm3s6965/lock.run | 5 + ci/expected/lm3s6965/message.run | 6 + ci/expected/lm3s6965/multilock.run | 1 + ci/expected/lm3s6965/not-sync.run | 3 + ci/expected/lm3s6965/only-shared-access.run | 2 + ci/expected/lm3s6965/periodic-at.run | 4 + ci/expected/lm3s6965/periodic-at2.run | 7 + ci/expected/lm3s6965/periodic.run | 4 + ci/expected/lm3s6965/peripherals-taken.run | 0 ci/expected/lm3s6965/pool.run | 0 ci/expected/lm3s6965/preempt.run | 5 + ci/expected/lm3s6965/prio-inversion.run | 6 + ci/expected/lm3s6965/ramfunc.run | 1 + ci/expected/lm3s6965/ramfunc.run.grep.bar | 1 + ci/expected/lm3s6965/ramfunc.run.grep.foo | 1 + ci/expected/lm3s6965/resource-user-struct.run | 2 + ci/expected/lm3s6965/schedule.run | 4 + ci/expected/lm3s6965/shared.run | 1 + ci/expected/lm3s6965/smallest.run | 0 ci/expected/lm3s6965/spawn.run | 2 + ci/expected/lm3s6965/spawn_arguments.run | 1 + ci/expected/lm3s6965/spawn_err.run | 3 + ci/expected/lm3s6965/spawn_loop.run | 7 + ci/expected/lm3s6965/static.run | 3 + ci/expected/lm3s6965/t-binds.run | 0 ci/expected/lm3s6965/t-cfg-resources.run | 0 ci/expected/lm3s6965/t-htask-main.run | 0 ci/expected/lm3s6965/t-idle-main.run | 0 ci/expected/lm3s6965/t-late-not-send.run | 0 ci/expected/lm3s6965/t-schedule.run | 0 ci/expected/lm3s6965/t-spawn.run | 0 ci/expected/lm3s6965/task.run | 5 + ci/expected/lm3s6965/zero-prio-task.run | 3 + examples/hifive1/.cargo/config.toml | 11 + examples/hifive1/Cargo.lock | 364 ++++++++++++++ examples/hifive1/Cargo.toml | 22 + examples/hifive1/examples/prio_inheritance.rs | 140 ++++++ examples/hifive1/examples/static.rs | 60 +++ examples/hifive1/examples/task.rs | 57 +++ examples/hifive1/examples/zero_prio_task.rs | 61 +++ examples/hifive1/rust-toolchain.toml | 4 + examples/lm3s6965/.cargo/config.toml | 13 + examples/lm3s6965/Cargo.lock | 527 +++++++++++++++++++++ examples/lm3s6965/Cargo.toml | 36 ++ examples/lm3s6965/examples/async-channel-done.rs | 65 +++ .../lm3s6965/examples/async-channel-no-receiver.rs | 37 ++ .../lm3s6965/examples/async-channel-no-sender.rs | 38 ++ examples/lm3s6965/examples/async-channel-try.rs | 56 +++ examples/lm3s6965/examples/async-channel.rs | 62 +++ examples/lm3s6965/examples/async-delay.rs | 58 +++ .../lm3s6965/examples/async-task-multiple-prios.rs | 93 ++++ examples/lm3s6965/examples/async-task.rs | 71 +++ examples/lm3s6965/examples/async-timeout.rs | 96 ++++ examples/lm3s6965/examples/big-struct-opt.rs | 80 ++++ examples/lm3s6965/examples/binds.rs | 54 +++ examples/lm3s6965/examples/common.rs | 86 ++++ examples/lm3s6965/examples/complex.rs | 129 +++++ examples/lm3s6965/examples/declared_locals.rs | 47 ++ examples/lm3s6965/examples/destructure.rs | 56 +++ examples/lm3s6965/examples/executor-size.rs | 42 ++ examples/lm3s6965/examples/extern_binds.rs | 59 +++ examples/lm3s6965/examples/extern_spawn.rs | 40 ++ examples/lm3s6965/examples/generics.rs | 67 +++ examples/lm3s6965/examples/hardware.rs | 60 +++ examples/lm3s6965/examples/idle-wfi.rs | 48 ++ examples/lm3s6965/examples/idle.rs | 41 ++ examples/lm3s6965/examples/init.rs | 42 ++ examples/lm3s6965/examples/locals.rs | 86 ++++ examples/lm3s6965/examples/lock-free.rs | 50 ++ examples/lm3s6965/examples/lock.rs | 72 +++ examples/lm3s6965/examples/multilock.rs | 56 +++ examples/lm3s6965/examples/not-sync.rs | 67 +++ examples/lm3s6965/examples/only-shared-access.rs | 43 ++ examples/lm3s6965/examples/peripherals-taken.rs | 28 ++ examples/lm3s6965/examples/pool.rs_old | 69 +++ examples/lm3s6965/examples/preempt.rs | 48 ++ examples/lm3s6965/examples/prio-inversion.rs | 86 ++++ examples/lm3s6965/examples/ramfunc.rs | 49 ++ examples/lm3s6965/examples/resource-user-struct.rs | 72 +++ examples/lm3s6965/examples/shared.rs | 51 ++ examples/lm3s6965/examples/smallest.rs | 27 ++ examples/lm3s6965/examples/spawn.rs | 35 ++ examples/lm3s6965/examples/spawn_arguments.rs | 34 ++ examples/lm3s6965/examples/spawn_err.rs | 39 ++ examples/lm3s6965/examples/spawn_loop.rs | 42 ++ examples/lm3s6965/examples/static.rs | 60 +++ examples/lm3s6965/examples/t-binds.rs | 45 ++ examples/lm3s6965/examples/t-cfg-resources.rs | 44 ++ examples/lm3s6965/examples/t-htask-main.rs | 32 ++ examples/lm3s6965/examples/t-idle-main.rs | 33 ++ examples/lm3s6965/examples/t-late-not-send.rs | 50 ++ examples/lm3s6965/examples/task.rs | 57 +++ examples/lm3s6965/examples/zero-prio-task.rs | 61 +++ rtic-macros/CHANGELOG.md | 1 + rtic-macros/Cargo.toml | 4 +- rtic-macros/src/codegen.rs | 1 + rtic-macros/src/codegen/async_dispatchers.rs | 7 +- rtic-macros/src/codegen/bindings.rs | 11 +- rtic-macros/src/codegen/bindings/cortex.rs | 18 +- rtic-macros/src/codegen/bindings/esp32c3.rs | 14 + rtic-macros/src/codegen/bindings/riscv_slic.rs | 255 ++++++++++ rtic-macros/src/codegen/bindings/template.rs | 60 ++- rtic-macros/src/codegen/extra_mods.rs | 9 + rtic-macros/src/codegen/main.rs | 16 +- rtic-macros/src/codegen/module.rs | 29 +- rtic-macros/src/codegen/pre_init.rs | 10 +- rtic-macros/src/codegen/util.rs | 2 - rtic-macros/src/lib.rs | 17 +- rtic-macros/src/preprocess.rs | 7 + rtic-macros/src/syntax.rs | 1 + rtic-macros/src/syntax/ast.rs | 10 +- rtic-macros/src/syntax/backend.rs | 32 ++ rtic-macros/src/syntax/backend/cortex.rs | 16 + rtic-macros/src/syntax/backend/esp32c3.rs | 16 + rtic-macros/src/syntax/backend/riscv_slic.rs | 16 + rtic-macros/src/syntax/backend/template.rs | 15 + rtic-macros/src/syntax/parse/app.rs | 28 ++ rtic-monotonics/CHANGELOG.md | 1 + rtic/.cargo/config.toml | 8 +- rtic/CHANGELOG.md | 1 + rtic/Cargo.toml | 14 +- rtic/build.rs | 51 +- rtic/ci/expected/async-channel-done.run | 9 - rtic/ci/expected/async-channel-no-receiver.run | 1 - rtic/ci/expected/async-channel-no-sender.run | 1 - rtic/ci/expected/async-channel-try.run | 2 - rtic/ci/expected/async-channel.run | 6 - rtic/ci/expected/async-delay.run | 7 - rtic/ci/expected/async-infinite-loop.run | 6 - rtic/ci/expected/async-task-multiple-prios.run | 6 - rtic/ci/expected/async-task.run | 5 - rtic/ci/expected/async-timeout.run | 16 - rtic/ci/expected/big-struct-opt.run | 3 - rtic/ci/expected/binds.run | 4 - rtic/ci/expected/cancel-reschedule.run | 3 - rtic/ci/expected/capacity.run | 5 - rtic/ci/expected/cfg-whole-task.run | 0 rtic/ci/expected/common.run | 3 - rtic/ci/expected/complex.run | 47 -- rtic/ci/expected/declared_locals.run | 0 rtic/ci/expected/destructure.run | 2 - rtic/ci/expected/executor-size.run | 1 - rtic/ci/expected/extern_binds.run | 4 - rtic/ci/expected/extern_spawn.run | 1 - rtic/ci/expected/generics.run | 6 - rtic/ci/expected/hardware.run | 4 - rtic/ci/expected/idle-wfi.run | 2 - rtic/ci/expected/idle.run | 2 - rtic/ci/expected/init.run | 1 - rtic/ci/expected/locals.run | 3 - rtic/ci/expected/lock-free.run | 2 - rtic/ci/expected/lock.run | 5 - rtic/ci/expected/message.run | 6 - rtic/ci/expected/multilock.run | 1 - rtic/ci/expected/not-sync.run | 3 - rtic/ci/expected/only-shared-access.run | 2 - rtic/ci/expected/periodic-at.run | 4 - rtic/ci/expected/periodic-at2.run | 7 - rtic/ci/expected/periodic.run | 4 - rtic/ci/expected/peripherals-taken.run | 0 rtic/ci/expected/pool.run | 0 rtic/ci/expected/preempt.run | 5 - rtic/ci/expected/prio-inversion.run | 6 - rtic/ci/expected/ramfunc.run | 1 - rtic/ci/expected/ramfunc.run.grep.bar | 1 - rtic/ci/expected/ramfunc.run.grep.foo | 1 - rtic/ci/expected/resource-user-struct.run | 2 - rtic/ci/expected/schedule.run | 4 - rtic/ci/expected/shared.run | 1 - rtic/ci/expected/smallest.run | 0 rtic/ci/expected/spawn.run | 2 - rtic/ci/expected/spawn_arguments.run | 1 - rtic/ci/expected/spawn_err.run | 3 - rtic/ci/expected/spawn_loop.run | 7 - rtic/ci/expected/static.run | 3 - rtic/ci/expected/t-binds.run | 0 rtic/ci/expected/t-cfg-resources.run | 0 rtic/ci/expected/t-htask-main.run | 0 rtic/ci/expected/t-idle-main.run | 0 rtic/ci/expected/t-late-not-send.run | 0 rtic/ci/expected/t-schedule.run | 0 rtic/ci/expected/t-spawn.run | 0 rtic/ci/expected/task.run | 5 - rtic/ci/expected/zero-prio-task.run | 3 - rtic/examples/async-channel-done.rs | 65 --- rtic/examples/async-channel-no-receiver.rs | 37 -- rtic/examples/async-channel-no-sender.rs | 38 -- rtic/examples/async-channel-try.rs | 56 --- rtic/examples/async-channel.rs | 62 --- rtic/examples/async-delay.rs | 58 --- rtic/examples/async-task-multiple-prios.rs | 93 ---- rtic/examples/async-task.rs | 71 --- rtic/examples/async-timeout.rs | 96 ---- rtic/examples/big-struct-opt.rs | 80 ---- rtic/examples/binds.rs | 54 --- rtic/examples/common.rs | 86 ---- rtic/examples/complex.rs | 129 ----- rtic/examples/declared_locals.rs | 47 -- rtic/examples/destructure.rs | 56 --- rtic/examples/executor-size.rs | 42 -- rtic/examples/extern_binds.rs | 59 --- rtic/examples/extern_spawn.rs | 40 -- rtic/examples/generics.rs | 67 --- rtic/examples/hardware.rs | 60 --- rtic/examples/idle-wfi.rs | 48 -- rtic/examples/idle.rs | 41 -- rtic/examples/init.rs | 42 -- rtic/examples/locals.rs | 86 ---- rtic/examples/lock-free.rs | 50 -- rtic/examples/lock.rs | 72 --- rtic/examples/multilock.rs | 56 --- rtic/examples/not-sync.rs | 67 --- rtic/examples/only-shared-access.rs | 43 -- rtic/examples/peripherals-taken.rs | 28 -- rtic/examples/pool.rs_old | 69 --- rtic/examples/preempt.rs | 48 -- rtic/examples/prio-inversion.rs | 86 ---- rtic/examples/ramfunc.rs | 49 -- rtic/examples/resource-user-struct.rs | 72 --- rtic/examples/shared.rs | 51 -- rtic/examples/smallest.rs | 27 -- rtic/examples/spawn.rs | 35 -- rtic/examples/spawn_arguments.rs | 34 -- rtic/examples/spawn_err.rs | 39 -- rtic/examples/spawn_loop.rs | 42 -- rtic/examples/static.rs | 60 --- rtic/examples/t-binds.rs | 45 -- rtic/examples/t-cfg-resources.rs | 44 -- rtic/examples/t-htask-main.rs | 32 -- rtic/examples/t-idle-main.rs | 33 -- rtic/examples/t-late-not-send.rs | 50 -- rtic/examples/task.rs | 57 --- rtic/examples/zero-prio-task.rs | 61 --- rtic/src/export.rs | 30 +- rtic/src/export/riscv_common.rs | 3 +- rtic/src/export/riscv_esp32c3.rs | 1 + rtic/src/export/slic.rs | 19 + rtic/src/lib.rs | 1 - xtask/src/argument_parsing.rs | 194 +++++--- xtask/src/cargo_command.rs | 71 ++- xtask/src/main.rs | 66 ++- xtask/src/run.rs | 78 ++- 277 files changed, 5300 insertions(+), 3293 deletions(-) create mode 100644 ci/expected/hifive1/prio_inheritance.run create mode 100644 ci/expected/hifive1/static.run create mode 100644 ci/expected/hifive1/task.run create mode 100644 ci/expected/hifive1/zero_prio_task.run create mode 100644 ci/expected/lm3s6965/async-channel-done.run create mode 100644 ci/expected/lm3s6965/async-channel-no-receiver.run create mode 100644 ci/expected/lm3s6965/async-channel-no-sender.run create mode 100644 ci/expected/lm3s6965/async-channel-try.run create mode 100644 ci/expected/lm3s6965/async-channel.run create mode 100644 ci/expected/lm3s6965/async-delay.run create mode 100644 ci/expected/lm3s6965/async-infinite-loop.run create mode 100644 ci/expected/lm3s6965/async-task-multiple-prios.run create mode 100644 ci/expected/lm3s6965/async-task.run create mode 100644 ci/expected/lm3s6965/async-timeout.run create mode 100644 ci/expected/lm3s6965/big-struct-opt.run create mode 100644 ci/expected/lm3s6965/binds.run create mode 100644 ci/expected/lm3s6965/cancel-reschedule.run create mode 100644 ci/expected/lm3s6965/capacity.run create mode 100644 ci/expected/lm3s6965/cfg-whole-task.run create mode 100644 ci/expected/lm3s6965/common.run create mode 100644 ci/expected/lm3s6965/complex.run create mode 100644 ci/expected/lm3s6965/declared_locals.run create mode 100644 ci/expected/lm3s6965/destructure.run create mode 100644 ci/expected/lm3s6965/executor-size.run create mode 100644 ci/expected/lm3s6965/extern_binds.run create mode 100644 ci/expected/lm3s6965/extern_spawn.run create mode 100644 ci/expected/lm3s6965/generics.run create mode 100644 ci/expected/lm3s6965/hardware.run create mode 100644 ci/expected/lm3s6965/idle-wfi.run create mode 100644 ci/expected/lm3s6965/idle.run create mode 100644 ci/expected/lm3s6965/init.run create mode 100644 ci/expected/lm3s6965/locals.run create mode 100644 ci/expected/lm3s6965/lock-free.run create mode 100644 ci/expected/lm3s6965/lock.run create mode 100644 ci/expected/lm3s6965/message.run create mode 100644 ci/expected/lm3s6965/multilock.run create mode 100644 ci/expected/lm3s6965/not-sync.run create mode 100644 ci/expected/lm3s6965/only-shared-access.run create mode 100644 ci/expected/lm3s6965/periodic-at.run create mode 100644 ci/expected/lm3s6965/periodic-at2.run create mode 100644 ci/expected/lm3s6965/periodic.run create mode 100644 ci/expected/lm3s6965/peripherals-taken.run create mode 100644 ci/expected/lm3s6965/pool.run create mode 100644 ci/expected/lm3s6965/preempt.run create mode 100644 ci/expected/lm3s6965/prio-inversion.run create mode 100644 ci/expected/lm3s6965/ramfunc.run create mode 100644 ci/expected/lm3s6965/ramfunc.run.grep.bar create mode 100644 ci/expected/lm3s6965/ramfunc.run.grep.foo create mode 100644 ci/expected/lm3s6965/resource-user-struct.run create mode 100644 ci/expected/lm3s6965/schedule.run create mode 100644 ci/expected/lm3s6965/shared.run create mode 100644 ci/expected/lm3s6965/smallest.run create mode 100644 ci/expected/lm3s6965/spawn.run create mode 100644 ci/expected/lm3s6965/spawn_arguments.run create mode 100644 ci/expected/lm3s6965/spawn_err.run create mode 100644 ci/expected/lm3s6965/spawn_loop.run create mode 100644 ci/expected/lm3s6965/static.run create mode 100644 ci/expected/lm3s6965/t-binds.run create mode 100644 ci/expected/lm3s6965/t-cfg-resources.run create mode 100644 ci/expected/lm3s6965/t-htask-main.run create mode 100644 ci/expected/lm3s6965/t-idle-main.run create mode 100644 ci/expected/lm3s6965/t-late-not-send.run create mode 100644 ci/expected/lm3s6965/t-schedule.run create mode 100644 ci/expected/lm3s6965/t-spawn.run create mode 100644 ci/expected/lm3s6965/task.run create mode 100644 ci/expected/lm3s6965/zero-prio-task.run create mode 100644 examples/hifive1/.cargo/config.toml create mode 100644 examples/hifive1/Cargo.lock create mode 100644 examples/hifive1/Cargo.toml create mode 100644 examples/hifive1/examples/prio_inheritance.rs create mode 100644 examples/hifive1/examples/static.rs create mode 100644 examples/hifive1/examples/task.rs create mode 100644 examples/hifive1/examples/zero_prio_task.rs create mode 100644 examples/hifive1/rust-toolchain.toml create mode 100644 examples/lm3s6965/.cargo/config.toml create mode 100644 examples/lm3s6965/Cargo.lock create mode 100644 examples/lm3s6965/Cargo.toml create mode 100644 examples/lm3s6965/examples/async-channel-done.rs create mode 100644 examples/lm3s6965/examples/async-channel-no-receiver.rs create mode 100644 examples/lm3s6965/examples/async-channel-no-sender.rs create mode 100644 examples/lm3s6965/examples/async-channel-try.rs create mode 100644 examples/lm3s6965/examples/async-channel.rs create mode 100644 examples/lm3s6965/examples/async-delay.rs create mode 100644 examples/lm3s6965/examples/async-task-multiple-prios.rs create mode 100644 examples/lm3s6965/examples/async-task.rs create mode 100644 examples/lm3s6965/examples/async-timeout.rs create mode 100644 examples/lm3s6965/examples/big-struct-opt.rs create mode 100644 examples/lm3s6965/examples/binds.rs create mode 100644 examples/lm3s6965/examples/common.rs create mode 100644 examples/lm3s6965/examples/complex.rs create mode 100644 examples/lm3s6965/examples/declared_locals.rs create mode 100644 examples/lm3s6965/examples/destructure.rs create mode 100644 examples/lm3s6965/examples/executor-size.rs create mode 100644 examples/lm3s6965/examples/extern_binds.rs create mode 100644 examples/lm3s6965/examples/extern_spawn.rs create mode 100644 examples/lm3s6965/examples/generics.rs create mode 100644 examples/lm3s6965/examples/hardware.rs create mode 100644 examples/lm3s6965/examples/idle-wfi.rs create mode 100644 examples/lm3s6965/examples/idle.rs create mode 100644 examples/lm3s6965/examples/init.rs create mode 100644 examples/lm3s6965/examples/locals.rs create mode 100644 examples/lm3s6965/examples/lock-free.rs create mode 100644 examples/lm3s6965/examples/lock.rs create mode 100644 examples/lm3s6965/examples/multilock.rs create mode 100644 examples/lm3s6965/examples/not-sync.rs create mode 100644 examples/lm3s6965/examples/only-shared-access.rs create mode 100644 examples/lm3s6965/examples/peripherals-taken.rs create mode 100644 examples/lm3s6965/examples/pool.rs_old create mode 100644 examples/lm3s6965/examples/preempt.rs create mode 100644 examples/lm3s6965/examples/prio-inversion.rs create mode 100644 examples/lm3s6965/examples/ramfunc.rs create mode 100644 examples/lm3s6965/examples/resource-user-struct.rs create mode 100644 examples/lm3s6965/examples/shared.rs create mode 100644 examples/lm3s6965/examples/smallest.rs create mode 100644 examples/lm3s6965/examples/spawn.rs create mode 100644 examples/lm3s6965/examples/spawn_arguments.rs create mode 100644 examples/lm3s6965/examples/spawn_err.rs create mode 100644 examples/lm3s6965/examples/spawn_loop.rs create mode 100644 examples/lm3s6965/examples/static.rs create mode 100644 examples/lm3s6965/examples/t-binds.rs create mode 100644 examples/lm3s6965/examples/t-cfg-resources.rs create mode 100644 examples/lm3s6965/examples/t-htask-main.rs create mode 100644 examples/lm3s6965/examples/t-idle-main.rs create mode 100644 examples/lm3s6965/examples/t-late-not-send.rs create mode 100644 examples/lm3s6965/examples/task.rs create mode 100644 examples/lm3s6965/examples/zero-prio-task.rs create mode 100644 rtic-macros/src/codegen/bindings/riscv_slic.rs create mode 100644 rtic-macros/src/codegen/extra_mods.rs create mode 100644 rtic-macros/src/preprocess.rs create mode 100644 rtic-macros/src/syntax/backend.rs create mode 100644 rtic-macros/src/syntax/backend/cortex.rs create mode 100644 rtic-macros/src/syntax/backend/esp32c3.rs create mode 100644 rtic-macros/src/syntax/backend/riscv_slic.rs create mode 100644 rtic-macros/src/syntax/backend/template.rs delete mode 100644 rtic/ci/expected/async-channel-done.run delete mode 100644 rtic/ci/expected/async-channel-no-receiver.run delete mode 100644 rtic/ci/expected/async-channel-no-sender.run delete mode 100644 rtic/ci/expected/async-channel-try.run delete mode 100644 rtic/ci/expected/async-channel.run delete mode 100644 rtic/ci/expected/async-delay.run delete mode 100644 rtic/ci/expected/async-infinite-loop.run delete mode 100644 rtic/ci/expected/async-task-multiple-prios.run delete mode 100644 rtic/ci/expected/async-task.run delete mode 100644 rtic/ci/expected/async-timeout.run delete mode 100644 rtic/ci/expected/big-struct-opt.run delete mode 100644 rtic/ci/expected/binds.run delete mode 100644 rtic/ci/expected/cancel-reschedule.run delete mode 100644 rtic/ci/expected/capacity.run delete mode 100644 rtic/ci/expected/cfg-whole-task.run delete mode 100644 rtic/ci/expected/common.run delete mode 100644 rtic/ci/expected/complex.run delete mode 100644 rtic/ci/expected/declared_locals.run delete mode 100644 rtic/ci/expected/destructure.run delete mode 100644 rtic/ci/expected/executor-size.run delete mode 100644 rtic/ci/expected/extern_binds.run delete mode 100644 rtic/ci/expected/extern_spawn.run delete mode 100644 rtic/ci/expected/generics.run delete mode 100644 rtic/ci/expected/hardware.run delete mode 100644 rtic/ci/expected/idle-wfi.run delete mode 100644 rtic/ci/expected/idle.run delete mode 100644 rtic/ci/expected/init.run delete mode 100644 rtic/ci/expected/locals.run delete mode 100644 rtic/ci/expected/lock-free.run delete mode 100644 rtic/ci/expected/lock.run delete mode 100644 rtic/ci/expected/message.run delete mode 100644 rtic/ci/expected/multilock.run delete mode 100644 rtic/ci/expected/not-sync.run delete mode 100644 rtic/ci/expected/only-shared-access.run delete mode 100644 rtic/ci/expected/periodic-at.run delete mode 100644 rtic/ci/expected/periodic-at2.run delete mode 100644 rtic/ci/expected/periodic.run delete mode 100644 rtic/ci/expected/peripherals-taken.run delete mode 100644 rtic/ci/expected/pool.run delete mode 100644 rtic/ci/expected/preempt.run delete mode 100644 rtic/ci/expected/prio-inversion.run delete mode 100644 rtic/ci/expected/ramfunc.run delete mode 100644 rtic/ci/expected/ramfunc.run.grep.bar delete mode 100644 rtic/ci/expected/ramfunc.run.grep.foo delete mode 100644 rtic/ci/expected/resource-user-struct.run delete mode 100644 rtic/ci/expected/schedule.run delete mode 100644 rtic/ci/expected/shared.run delete mode 100644 rtic/ci/expected/smallest.run delete mode 100644 rtic/ci/expected/spawn.run delete mode 100644 rtic/ci/expected/spawn_arguments.run delete mode 100644 rtic/ci/expected/spawn_err.run delete mode 100644 rtic/ci/expected/spawn_loop.run delete mode 100644 rtic/ci/expected/static.run delete mode 100644 rtic/ci/expected/t-binds.run delete mode 100644 rtic/ci/expected/t-cfg-resources.run delete mode 100644 rtic/ci/expected/t-htask-main.run delete mode 100644 rtic/ci/expected/t-idle-main.run delete mode 100644 rtic/ci/expected/t-late-not-send.run delete mode 100644 rtic/ci/expected/t-schedule.run delete mode 100644 rtic/ci/expected/t-spawn.run delete mode 100644 rtic/ci/expected/task.run delete mode 100644 rtic/ci/expected/zero-prio-task.run delete mode 100644 rtic/examples/async-channel-done.rs delete mode 100644 rtic/examples/async-channel-no-receiver.rs delete mode 100644 rtic/examples/async-channel-no-sender.rs delete mode 100644 rtic/examples/async-channel-try.rs delete mode 100644 rtic/examples/async-channel.rs delete mode 100644 rtic/examples/async-delay.rs delete mode 100644 rtic/examples/async-task-multiple-prios.rs delete mode 100644 rtic/examples/async-task.rs delete mode 100644 rtic/examples/async-timeout.rs delete mode 100644 rtic/examples/big-struct-opt.rs delete mode 100644 rtic/examples/binds.rs delete mode 100644 rtic/examples/common.rs delete mode 100644 rtic/examples/complex.rs delete mode 100644 rtic/examples/declared_locals.rs delete mode 100644 rtic/examples/destructure.rs delete mode 100644 rtic/examples/executor-size.rs delete mode 100644 rtic/examples/extern_binds.rs delete mode 100644 rtic/examples/extern_spawn.rs delete mode 100644 rtic/examples/generics.rs delete mode 100644 rtic/examples/hardware.rs delete mode 100644 rtic/examples/idle-wfi.rs delete mode 100644 rtic/examples/idle.rs delete mode 100644 rtic/examples/init.rs delete mode 100644 rtic/examples/locals.rs delete mode 100644 rtic/examples/lock-free.rs delete mode 100644 rtic/examples/lock.rs delete mode 100644 rtic/examples/multilock.rs delete mode 100644 rtic/examples/not-sync.rs delete mode 100644 rtic/examples/only-shared-access.rs delete mode 100644 rtic/examples/peripherals-taken.rs delete mode 100644 rtic/examples/pool.rs_old delete mode 100644 rtic/examples/preempt.rs delete mode 100644 rtic/examples/prio-inversion.rs delete mode 100644 rtic/examples/ramfunc.rs delete mode 100644 rtic/examples/resource-user-struct.rs delete mode 100644 rtic/examples/shared.rs delete mode 100644 rtic/examples/smallest.rs delete mode 100644 rtic/examples/spawn.rs delete mode 100644 rtic/examples/spawn_arguments.rs delete mode 100644 rtic/examples/spawn_err.rs delete mode 100644 rtic/examples/spawn_loop.rs delete mode 100644 rtic/examples/static.rs delete mode 100644 rtic/examples/t-binds.rs delete mode 100644 rtic/examples/t-cfg-resources.rs delete mode 100644 rtic/examples/t-htask-main.rs delete mode 100644 rtic/examples/t-idle-main.rs delete mode 100644 rtic/examples/t-late-not-send.rs delete mode 100644 rtic/examples/task.rs delete mode 100644 rtic/examples/zero-prio-task.rs create mode 100644 rtic/src/export/slic.rs diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 578ca40..3a4ed8f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,9 +31,9 @@ jobs: - name: cargo xtask fmt run: cargo xtask --verbose fmt -c - # Compilation check - check: - name: check + # Compilation check (lm3s6965) + checklm3s6965: + name: check (lm3s6965) runs-on: ubuntu-22.04 strategy: matrix: @@ -62,11 +62,14 @@ jobs: - name: Cache Dependencies uses: Swatinem/rust-cache@v2 - - run: cargo xtask --deny-warnings --backend ${{ matrix.backend }} check + - run: cargo xtask --deny-warnings --platform lm3s6965 --backend ${{ matrix.backend }} check - # Clippy - clippy: - name: clippy + # Compilation check (hifive1) TODO + # checkhifive1: + + # Clippy (lm3s6965) + clippylm3s6965: + name: clippy (lm3s6965) runs-on: ubuntu-22.04 strategy: matrix: @@ -98,11 +101,14 @@ jobs: - name: Cache Dependencies uses: Swatinem/rust-cache@v2 - - run: cargo xtask --deny-warnings --backend ${{ matrix.backend }} clippy + - run: cargo xtask --deny-warnings --platform lm3s6965 --backend ${{ matrix.backend }} clippy + + # Clippy (hifive1) TODO + # clippyhifive1: - # Verify all examples, checks - checkexamples: - name: check examples + # Platform lm3s6965: verify all examples, checks + checkexampleslm3s6965: + name: check examples (lm3s6965) runs-on: ubuntu-22.04 strategy: matrix: @@ -133,44 +139,46 @@ jobs: - name: Check the examples if: ${{ matrix.backend == 'thumbv8-base' }} - run: cargo xtask --backend ${{ matrix.backend }} --exampleexclude pool example-check + run: cargo xtask --platform lm3s6965 --backend ${{ matrix.backend }} --exampleexclude pool example-check - name: Check the examples if: ${{ matrix.backend != 'thumbv8-base' }} - run: cargo xtask --backend ${{ matrix.backend }} example-check - - # Check that the usage examples build - usageexamples: - name: Build usage examples + run: cargo xtask --platform lm3s6965 --backend ${{ matrix.backend }} example-check + + # Platform hifive1: verify all examples, checks + checkexampleshifive1: + name: check examples (hifive1) runs-on: ubuntu-22.04 strategy: matrix: + backend: + - riscv32-imc-clint + - riscv32-imac-clint toolchain: - stable steps: - name: Checkout uses: actions/checkout@v4 - - name: Install rust ${{ matrix.toolchain }} + - name: Install Rust ${{ matrix.toolchain }} run: | - rustup set profile minimal rustup override set ${{ matrix.toolchain }} - - name: Configure rust target (v6, v7) + - name: Configure Rust target run: | - rustup target add thumbv7em-none-eabihf - rustup target add thumbv7m-none-eabi - rustup target add thumbv6m-none-eabi - rustup component add rust-src + rustup target add riscv32imac-unknown-none-elf + rustup target add riscv32imc-unknown-none-elf - name: Cache Dependencies uses: Swatinem/rust-cache@v2 - - - name: Install flip-link - run: cargo install flip-link + + - name: Check the examples + if: ${{ matrix.backend == 'riscv32-imc-clint' }} + run: cargo xtask --platform hifive1 --backend ${{ matrix.backend }} --exampleexclude static example-check - name: Check the examples - run: cargo xtask usage-example-build + if: ${{ matrix.backend != 'riscv32-imc-clint' }} + run: cargo xtask --platform hifive1 --backend ${{ matrix.backend }} example-check buildqemu: name: Get modern QEMU, build and store @@ -192,7 +200,7 @@ jobs: - name: Install QEMU to get dependencies run: | sudo apt update - sudo apt install -y qemu-system-arm + sudo apt install -y qemu-system-arm qemu-system-riscv32 sudo apt-get install git libglib2.0-dev libfdt-dev libpixman-1-dev zlib1g-dev ninja-build - if: ${{ steps.cache-qemu.outputs.cache-hit != 'true' }} @@ -226,9 +234,9 @@ jobs: name: qemu path: qemu.tar - # Verify the example output with run-pass tests - testexamples: - name: QEMU run + # Platform lm3s6965: verify the example output with run-pass tests + testexampleslm3s6965: + name: QEMU run (lm3s6965) needs: buildqemu runs-on: ubuntu-22.04 strategy: @@ -283,7 +291,71 @@ jobs: which qemu-system-riscv32 - name: Run-pass tests - run: cargo xtask --deny-warnings --backend ${{ matrix.backend }} qemu + run: cargo xtask --deny-warnings --platform lm3s6965 --backend ${{ matrix.backend }} qemu + + # Platform hifive1: verify the example output with run-pass tests + testexampleshifive1: + name: QEMU run (hifive1) + needs: buildqemu + runs-on: ubuntu-22.04 + strategy: + matrix: + backend: + - riscv32-imc-clint + - riscv32-imac-clint + toolchain: + - stable + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Rust ${{ matrix.toolchain }} + run: | + rustup set profile minimal + rustup override set ${{ matrix.toolchain }} + + - name: Configure Rust target + run: | + rustup target add riscv32imac-unknown-none-elf + rustup target add riscv32imc-unknown-none-elf + + - name: Add Rust component llvm-tools-preview + run: rustup component add llvm-tools-preview + + # Use precompiled binutils + - name: Install cargo-binutils + uses: taiki-e/install-action@v2 + with: + tool: cargo-binutils + + - name: Cache Dependencies + uses: Swatinem/rust-cache@v2 + + - name: Install QEMU to get dependencies + run: | + sudo apt update + sudo apt install -y qemu-system-riscv32 + + - name: Download built QEMU + uses: actions/download-artifact@v4 + with: + name: qemu + + - name: Extract QEMU into local path + run: tar -xf qemu.tar -C /usr/local/bin + + - name: Check which QEMU is used + run: | + which qemu-system-arm + which qemu-system-riscv32 + + - name: Run-pass tests + if: ${{ matrix.backend == 'riscv32-imc-clint' }} + run: cargo xtask --deny-warnings --platform hifive1 --backend ${{ matrix.backend }} --exampleexclude static qemu + + - name: Run-pass tests + if: ${{ matrix.backend != 'riscv32-imc-clint' }} + run: cargo xtask --deny-warnings --platform hifive1 --backend ${{ matrix.backend }} qemu # Run test suite tests: @@ -719,10 +791,14 @@ jobs: if: github.event_name == 'push' && success() needs: - formatcheck - - check - - clippy - - checkexamples - - testexamples + - checklm3s6965 + # checkhifive1 TODO + - clippylm3s6965 + # clippyhifive1 TODO + - checkexampleslm3s6965 + - checkexampleshifive1 + - testexampleslm3s6965 + - testexampleshifive1 - tests - docs - mdbook diff --git a/.gitignore b/.gitignore index d081dc3..88b19b5 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ Cargo.lock *.hex book-target/ + +.DS_Store +.vscode/ diff --git a/ci/expected/hifive1/prio_inheritance.run b/ci/expected/hifive1/prio_inheritance.run new file mode 100644 index 0000000..c60b241 --- /dev/null +++ b/ci/expected/hifive1/prio_inheritance.run @@ -0,0 +1,17 @@ +[Idle]: Started + [SoftMedium]: Started + [SoftMedium]: Shared: 1 + [SoftHigh]: Started + [SoftHigh]: Shared: 2 + [SoftHigh]: Finished + [SoftMedium]: Finished + [SoftLow1]: Started + [SoftLow1]: Shared: 3 + [SoftLow1]: Yield + [SoftLow2]: Started + [SoftLow2]: Shared: 4 + [SoftLow2]: Yield + [SoftLow1]: Finished + [SoftLow2]: Finished +[Idle]: Shared: 4 +[Idle]: Finished diff --git a/ci/expected/hifive1/static.run b/ci/expected/hifive1/static.run new file mode 100644 index 0000000..3d3f46f --- /dev/null +++ b/ci/expected/hifive1/static.run @@ -0,0 +1,3 @@ +received message: 1 +received message: 2 +received message: 3 diff --git a/ci/expected/hifive1/task.run b/ci/expected/hifive1/task.run new file mode 100644 index 0000000..de45dce --- /dev/null +++ b/ci/expected/hifive1/task.run @@ -0,0 +1,5 @@ +foo - start +foo - middle +baz +foo - end +bar diff --git a/ci/expected/hifive1/zero_prio_task.run b/ci/expected/hifive1/zero_prio_task.run new file mode 100644 index 0000000..123b0f2 --- /dev/null +++ b/ci/expected/hifive1/zero_prio_task.run @@ -0,0 +1,3 @@ +init +hello from async +hello from async2 diff --git a/ci/expected/lm3s6965/async-channel-done.run b/ci/expected/lm3s6965/async-channel-done.run new file mode 100644 index 0000000..525962a --- /dev/null +++ b/ci/expected/lm3s6965/async-channel-done.run @@ -0,0 +1,9 @@ +Sender 1 sending: 1 +Sender 1 done +Sender 2 sending: 2 +Sender 3 sending: 3 +Receiver got: 1 +Sender 2 done +Receiver got: 2 +Sender 3 done +Receiver got: 3 diff --git a/ci/expected/lm3s6965/async-channel-no-receiver.run b/ci/expected/lm3s6965/async-channel-no-receiver.run new file mode 100644 index 0000000..34624e1 --- /dev/null +++ b/ci/expected/lm3s6965/async-channel-no-receiver.run @@ -0,0 +1 @@ +Sender 1 sending: 1 Err(NoReceiver(1)) diff --git a/ci/expected/lm3s6965/async-channel-no-sender.run b/ci/expected/lm3s6965/async-channel-no-sender.run new file mode 100644 index 0000000..237f2f1 --- /dev/null +++ b/ci/expected/lm3s6965/async-channel-no-sender.run @@ -0,0 +1 @@ +Receiver got: Err(NoSender) diff --git a/ci/expected/lm3s6965/async-channel-try.run b/ci/expected/lm3s6965/async-channel-try.run new file mode 100644 index 0000000..c3a4092 --- /dev/null +++ b/ci/expected/lm3s6965/async-channel-try.run @@ -0,0 +1,2 @@ +Sender 1 sending: 1 +Sender 1 try sending: 2 Err(Full(2)) diff --git a/ci/expected/lm3s6965/async-channel.run b/ci/expected/lm3s6965/async-channel.run new file mode 100644 index 0000000..4e313a1 --- /dev/null +++ b/ci/expected/lm3s6965/async-channel.run @@ -0,0 +1,6 @@ +Sender 1 sending: 1 +Sender 2 sending: 2 +Sender 3 sending: 3 +Receiver got: 1 +Receiver got: 2 +Receiver got: 3 diff --git a/ci/expected/lm3s6965/async-delay.run b/ci/expected/lm3s6965/async-delay.run new file mode 100644 index 0000000..61852ab --- /dev/null +++ b/ci/expected/lm3s6965/async-delay.run @@ -0,0 +1,7 @@ +init +hello from bar +hello from baz +hello from foo +bye from foo +bye from bar +bye from baz diff --git a/ci/expected/lm3s6965/async-infinite-loop.run b/ci/expected/lm3s6965/async-infinite-loop.run new file mode 100644 index 0000000..f9fd4e4 --- /dev/null +++ b/ci/expected/lm3s6965/async-infinite-loop.run @@ -0,0 +1,6 @@ +init +hello from async 0 +hello from async 1 +hello from async 2 +hello from async 3 +hello from async 4 diff --git a/ci/expected/lm3s6965/async-task-multiple-prios.run b/ci/expected/lm3s6965/async-task-multiple-prios.run new file mode 100644 index 0000000..0b42df0 --- /dev/null +++ b/ci/expected/lm3s6965/async-task-multiple-prios.run @@ -0,0 +1,6 @@ +init +hello from async 3 a 1 +hello from async 4 a 2 +hello from async 1 a 3 +hello from async 2 a 4 +idle diff --git a/ci/expected/lm3s6965/async-task.run b/ci/expected/lm3s6965/async-task.run new file mode 100644 index 0000000..1f93a4c --- /dev/null +++ b/ci/expected/lm3s6965/async-task.run @@ -0,0 +1,5 @@ +init +hello from async2 +hello from async +hello from async with args a: 1, b: 2 +idle diff --git a/ci/expected/lm3s6965/async-timeout.run b/ci/expected/lm3s6965/async-timeout.run new file mode 100644 index 0000000..6b4c089 --- /dev/null +++ b/ci/expected/lm3s6965/async-timeout.run @@ -0,0 +1,16 @@ +init +the hal takes a duration of Duration { ticks: 45 } +timeout +the hal takes a duration of Duration { ticks: 45 } +hal returned 5 +the hal takes a duration of Duration { ticks: 45 } +hal returned 5 +now is Instant { ticks: 213 }, timeout at Instant { ticks: 263 } +the hal takes a duration of Duration { ticks: 35 } +hal returned 5 at time Instant { ticks: 249 } +now is Instant { ticks: 313 }, timeout at Instant { ticks: 363 } +the hal takes a duration of Duration { ticks: 45 } +hal returned 5 at time Instant { ticks: 359 } +now is Instant { ticks: 413 }, timeout at Instant { ticks: 463 } +the hal takes a duration of Duration { ticks: 55 } +timeout diff --git a/ci/expected/lm3s6965/big-struct-opt.run b/ci/expected/lm3s6965/big-struct-opt.run new file mode 100644 index 0000000..7fdef35 --- /dev/null +++ b/ci/expected/lm3s6965/big-struct-opt.run @@ -0,0 +1,3 @@ +async_task data:[22, 22, 22, 22, 22] +uart0 data:[22, 22, 22, 22, 22] +idle diff --git a/ci/expected/lm3s6965/binds.run b/ci/expected/lm3s6965/binds.run new file mode 100644 index 0000000..f84cff0 --- /dev/null +++ b/ci/expected/lm3s6965/binds.run @@ -0,0 +1,4 @@ +init +foo called 1 time +idle +foo called 2 times diff --git a/ci/expected/lm3s6965/cancel-reschedule.run b/ci/expected/lm3s6965/cancel-reschedule.run new file mode 100644 index 0000000..5a94752 --- /dev/null +++ b/ci/expected/lm3s6965/cancel-reschedule.run @@ -0,0 +1,3 @@ +init +foo +bar diff --git a/ci/expected/lm3s6965/capacity.run b/ci/expected/lm3s6965/capacity.run new file mode 100644 index 0000000..f96815d --- /dev/null +++ b/ci/expected/lm3s6965/capacity.run @@ -0,0 +1,5 @@ +foo(0) +foo(1) +foo(2) +foo(3) +bar diff --git a/ci/expected/lm3s6965/cfg-whole-task.run b/ci/expected/lm3s6965/cfg-whole-task.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/common.run b/ci/expected/lm3s6965/common.run new file mode 100644 index 0000000..4f1d350 --- /dev/null +++ b/ci/expected/lm3s6965/common.run @@ -0,0 +1,3 @@ +bar: local_to_bar = 1 +foo: local_to_foo = 1 +idle: local_to_idle = 1 diff --git a/ci/expected/lm3s6965/complex.run b/ci/expected/lm3s6965/complex.run new file mode 100644 index 0000000..5df884d --- /dev/null +++ b/ci/expected/lm3s6965/complex.run @@ -0,0 +1,47 @@ +init +idle p0 started +t2 p4 called 1 time +enter lock s4 0 +t3 p4 exit +idle enter lock s3 0 +idle pend t0 +idle pend t1 +idle pend t2 +t2 p4 called 2 times +enter lock s4 1 +t3 p4 exit +idle still in lock s3 0 +t1 p3 called 1 time +t1 enter lock s4 2 +t1 pend t0 +t1 pend t2 +t1 still in lock s4 2 +t2 p4 called 3 times +enter lock s4 2 +t3 p4 exit +t1 p3 exit +t0 p2 called 1 time +t0 p2 exit + +back in idle +enter lock s2 0 +idle pend t0 +idle pend t1 +t1 p3 called 2 times +t1 enter lock s4 3 +t1 pend t0 +t1 pend t2 +t1 still in lock s4 3 +t2 p4 called 4 times +enter lock s4 3 +t3 p4 exit +t1 p3 exit +idle pend t2 +t2 p4 called 5 times +enter lock s4 4 +t3 p4 exit +idle still in lock s2 0 +t0 p2 called 2 times +t0 p2 exit + +idle exit diff --git a/ci/expected/lm3s6965/declared_locals.run b/ci/expected/lm3s6965/declared_locals.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/destructure.run b/ci/expected/lm3s6965/destructure.run new file mode 100644 index 0000000..25a4b1b --- /dev/null +++ b/ci/expected/lm3s6965/destructure.run @@ -0,0 +1,2 @@ +bar: a = 0, b = 1, c = 2 +foo: a = 0, b = 1, c = 2 diff --git a/ci/expected/lm3s6965/executor-size.run b/ci/expected/lm3s6965/executor-size.run new file mode 100644 index 0000000..2bb0d06 --- /dev/null +++ b/ci/expected/lm3s6965/executor-size.run @@ -0,0 +1 @@ +init, total executor size = 9 diff --git a/ci/expected/lm3s6965/extern_binds.run b/ci/expected/lm3s6965/extern_binds.run new file mode 100644 index 0000000..9d925d5 --- /dev/null +++ b/ci/expected/lm3s6965/extern_binds.run @@ -0,0 +1,4 @@ +init +foo called +idle +foo called diff --git a/ci/expected/lm3s6965/extern_spawn.run b/ci/expected/lm3s6965/extern_spawn.run new file mode 100644 index 0000000..257cc56 --- /dev/null +++ b/ci/expected/lm3s6965/extern_spawn.run @@ -0,0 +1 @@ +foo diff --git a/ci/expected/lm3s6965/generics.run b/ci/expected/lm3s6965/generics.run new file mode 100644 index 0000000..fb31731 --- /dev/null +++ b/ci/expected/lm3s6965/generics.run @@ -0,0 +1,6 @@ +UART1(STATE = 0) +shared: 0 -> 1 +UART0(STATE = 0) +shared: 1 -> 2 +UART1(STATE = 1) +shared: 2 -> 4 diff --git a/ci/expected/lm3s6965/hardware.run b/ci/expected/lm3s6965/hardware.run new file mode 100644 index 0000000..ef00864 --- /dev/null +++ b/ci/expected/lm3s6965/hardware.run @@ -0,0 +1,4 @@ +init +UART0 called 1 time +idle +UART0 called 2 times diff --git a/ci/expected/lm3s6965/idle-wfi.run b/ci/expected/lm3s6965/idle-wfi.run new file mode 100644 index 0000000..4307776 --- /dev/null +++ b/ci/expected/lm3s6965/idle-wfi.run @@ -0,0 +1,2 @@ +init +idle diff --git a/ci/expected/lm3s6965/idle.run b/ci/expected/lm3s6965/idle.run new file mode 100644 index 0000000..4307776 --- /dev/null +++ b/ci/expected/lm3s6965/idle.run @@ -0,0 +1,2 @@ +init +idle diff --git a/ci/expected/lm3s6965/init.run b/ci/expected/lm3s6965/init.run new file mode 100644 index 0000000..b1b7161 --- /dev/null +++ b/ci/expected/lm3s6965/init.run @@ -0,0 +1 @@ +init diff --git a/ci/expected/lm3s6965/locals.run b/ci/expected/lm3s6965/locals.run new file mode 100644 index 0000000..4f1d350 --- /dev/null +++ b/ci/expected/lm3s6965/locals.run @@ -0,0 +1,3 @@ +bar: local_to_bar = 1 +foo: local_to_foo = 1 +idle: local_to_idle = 1 diff --git a/ci/expected/lm3s6965/lock-free.run b/ci/expected/lm3s6965/lock-free.run new file mode 100644 index 0000000..18de0ec --- /dev/null +++ b/ci/expected/lm3s6965/lock-free.run @@ -0,0 +1,2 @@ + foo = 1 + bar = 2 diff --git a/ci/expected/lm3s6965/lock.run b/ci/expected/lm3s6965/lock.run new file mode 100644 index 0000000..a987b37 --- /dev/null +++ b/ci/expected/lm3s6965/lock.run @@ -0,0 +1,5 @@ +A +B - shared = 1 +C +D - shared = 2 +E diff --git a/ci/expected/lm3s6965/message.run b/ci/expected/lm3s6965/message.run new file mode 100644 index 0000000..11814db --- /dev/null +++ b/ci/expected/lm3s6965/message.run @@ -0,0 +1,6 @@ +foo +bar(0) +baz(1, 2) +foo +bar(1) +baz(2, 3) diff --git a/ci/expected/lm3s6965/multilock.run b/ci/expected/lm3s6965/multilock.run new file mode 100644 index 0000000..dd8c1f2 --- /dev/null +++ b/ci/expected/lm3s6965/multilock.run @@ -0,0 +1 @@ +Multiple locks, s1: 1, s2: 1, s3: 1 diff --git a/ci/expected/lm3s6965/not-sync.run b/ci/expected/lm3s6965/not-sync.run new file mode 100644 index 0000000..cd91476 --- /dev/null +++ b/ci/expected/lm3s6965/not-sync.run @@ -0,0 +1,3 @@ +init +bar a 13 +foo a 13 diff --git a/ci/expected/lm3s6965/only-shared-access.run b/ci/expected/lm3s6965/only-shared-access.run new file mode 100644 index 0000000..dcc73e6 --- /dev/null +++ b/ci/expected/lm3s6965/only-shared-access.run @@ -0,0 +1,2 @@ +bar(key = 0xdeadbeef) +foo(key = 0xdeadbeef) diff --git a/ci/expected/lm3s6965/periodic-at.run b/ci/expected/lm3s6965/periodic-at.run new file mode 100644 index 0000000..bf5bb06 --- /dev/null +++ b/ci/expected/lm3s6965/periodic-at.run @@ -0,0 +1,4 @@ +foo Instant { ticks: 0 } +foo Instant { ticks: 10 } +foo Instant { ticks: 20 } +foo Instant { ticks: 30 } diff --git a/ci/expected/lm3s6965/periodic-at2.run b/ci/expected/lm3s6965/periodic-at2.run new file mode 100644 index 0000000..6e56421 --- /dev/null +++ b/ci/expected/lm3s6965/periodic-at2.run @@ -0,0 +1,7 @@ +foo Instant { ticks: 0 } +bar Instant { ticks: 10 } +foo Instant { ticks: 30 } +bar Instant { ticks: 40 } +foo Instant { ticks: 60 } +bar Instant { ticks: 70 } +foo Instant { ticks: 90 } diff --git a/ci/expected/lm3s6965/periodic.run b/ci/expected/lm3s6965/periodic.run new file mode 100644 index 0000000..a1f8944 --- /dev/null +++ b/ci/expected/lm3s6965/periodic.run @@ -0,0 +1,4 @@ +foo +foo +foo +foo diff --git a/ci/expected/lm3s6965/peripherals-taken.run b/ci/expected/lm3s6965/peripherals-taken.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/pool.run b/ci/expected/lm3s6965/pool.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/preempt.run b/ci/expected/lm3s6965/preempt.run new file mode 100644 index 0000000..932b2b3 --- /dev/null +++ b/ci/expected/lm3s6965/preempt.run @@ -0,0 +1,5 @@ +foo - start + baz - start + baz - end + bar +foo - end diff --git a/ci/expected/lm3s6965/prio-inversion.run b/ci/expected/lm3s6965/prio-inversion.run new file mode 100644 index 0000000..9191436 --- /dev/null +++ b/ci/expected/lm3s6965/prio-inversion.run @@ -0,0 +1,6 @@ +foo - start +pre baz spawn 0 0 +post baz spawn 0 0 + baz - start + baz - end +foo - end diff --git a/ci/expected/lm3s6965/ramfunc.run b/ci/expected/lm3s6965/ramfunc.run new file mode 100644 index 0000000..257cc56 --- /dev/null +++ b/ci/expected/lm3s6965/ramfunc.run @@ -0,0 +1 @@ +foo diff --git a/ci/expected/lm3s6965/ramfunc.run.grep.bar b/ci/expected/lm3s6965/ramfunc.run.grep.bar new file mode 100644 index 0000000..33e002f --- /dev/null +++ b/ci/expected/lm3s6965/ramfunc.run.grep.bar @@ -0,0 +1 @@ +20000000 t ramfunc::bar::h9d6714fe5a3b0c89 diff --git a/ci/expected/lm3s6965/ramfunc.run.grep.foo b/ci/expected/lm3s6965/ramfunc.run.grep.foo new file mode 100644 index 0000000..44e8822 --- /dev/null +++ b/ci/expected/lm3s6965/ramfunc.run.grep.foo @@ -0,0 +1 @@ +00000162 t ramfunc::foo::h30e7789b08c08e19 diff --git a/ci/expected/lm3s6965/resource-user-struct.run b/ci/expected/lm3s6965/resource-user-struct.run new file mode 100644 index 0000000..a587a94 --- /dev/null +++ b/ci/expected/lm3s6965/resource-user-struct.run @@ -0,0 +1,2 @@ +UART0: shared = 1 +UART1: shared = 2 diff --git a/ci/expected/lm3s6965/schedule.run b/ci/expected/lm3s6965/schedule.run new file mode 100644 index 0000000..1dbd445 --- /dev/null +++ b/ci/expected/lm3s6965/schedule.run @@ -0,0 +1,4 @@ +init +foo +bar +baz diff --git a/ci/expected/lm3s6965/shared.run b/ci/expected/lm3s6965/shared.run new file mode 100644 index 0000000..6d3d3e4 --- /dev/null +++ b/ci/expected/lm3s6965/shared.run @@ -0,0 +1 @@ +received message: 42 diff --git a/ci/expected/lm3s6965/smallest.run b/ci/expected/lm3s6965/smallest.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/spawn.run b/ci/expected/lm3s6965/spawn.run new file mode 100644 index 0000000..240cd18 --- /dev/null +++ b/ci/expected/lm3s6965/spawn.run @@ -0,0 +1,2 @@ +init +foo diff --git a/ci/expected/lm3s6965/spawn_arguments.run b/ci/expected/lm3s6965/spawn_arguments.run new file mode 100644 index 0000000..9085e13 --- /dev/null +++ b/ci/expected/lm3s6965/spawn_arguments.run @@ -0,0 +1 @@ +foo 1, 1 diff --git a/ci/expected/lm3s6965/spawn_err.run b/ci/expected/lm3s6965/spawn_err.run new file mode 100644 index 0000000..97c4112 --- /dev/null +++ b/ci/expected/lm3s6965/spawn_err.run @@ -0,0 +1,3 @@ +init +Cannot spawn a spawned (running) task! +foo diff --git a/ci/expected/lm3s6965/spawn_loop.run b/ci/expected/lm3s6965/spawn_loop.run new file mode 100644 index 0000000..ee6e1e3 --- /dev/null +++ b/ci/expected/lm3s6965/spawn_loop.run @@ -0,0 +1,7 @@ +init +foo +idle +foo +idle +foo +idle diff --git a/ci/expected/lm3s6965/static.run b/ci/expected/lm3s6965/static.run new file mode 100644 index 0000000..3d3f46f --- /dev/null +++ b/ci/expected/lm3s6965/static.run @@ -0,0 +1,3 @@ +received message: 1 +received message: 2 +received message: 3 diff --git a/ci/expected/lm3s6965/t-binds.run b/ci/expected/lm3s6965/t-binds.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/t-cfg-resources.run b/ci/expected/lm3s6965/t-cfg-resources.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/t-htask-main.run b/ci/expected/lm3s6965/t-htask-main.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/t-idle-main.run b/ci/expected/lm3s6965/t-idle-main.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/t-late-not-send.run b/ci/expected/lm3s6965/t-late-not-send.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/t-schedule.run b/ci/expected/lm3s6965/t-schedule.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/t-spawn.run b/ci/expected/lm3s6965/t-spawn.run new file mode 100644 index 0000000..e69de29 diff --git a/ci/expected/lm3s6965/task.run b/ci/expected/lm3s6965/task.run new file mode 100644 index 0000000..de45dce --- /dev/null +++ b/ci/expected/lm3s6965/task.run @@ -0,0 +1,5 @@ +foo - start +foo - middle +baz +foo - end +bar diff --git a/ci/expected/lm3s6965/zero-prio-task.run b/ci/expected/lm3s6965/zero-prio-task.run new file mode 100644 index 0000000..123b0f2 --- /dev/null +++ b/ci/expected/lm3s6965/zero-prio-task.run @@ -0,0 +1,3 @@ +init +hello from async +hello from async2 diff --git a/examples/hifive1/.cargo/config.toml b/examples/hifive1/.cargo/config.toml new file mode 100644 index 0000000..2ce90b2 --- /dev/null +++ b/examples/hifive1/.cargo/config.toml @@ -0,0 +1,11 @@ +[target.'cfg(all(target_arch = "riscv32", target_os = "none"))'] +runner = "qemu-system-riscv32 -machine sifive_e,revb=true -nographic -semihosting-config enable=on,target=native -kernel" +# runner = "riscv64-unknown-elf-gdb -q -x gdb_init" +rustflags = [ + "-C", "link-arg=-Thifive1-link.x", +] + +[build] +# Pick ONE of these compilation targets +# target = "riscv32imc-unknown-none-elf" # non-atomic support +target = "riscv32imac-unknown-none-elf" # atomic support (partial) diff --git a/examples/hifive1/Cargo.lock b/examples/hifive1/Cargo.lock new file mode 100644 index 0000000..7cd694c --- /dev/null +++ b/examples/hifive1/Cargo.lock @@ -0,0 +1,364 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + +[[package]] +name = "bare-metal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "e310x" +version = "0.11.0" +source = "git+https://github.com/greenlsi/e310x.git?branch=master#50536cc5be2fd6adf7f879f002fdd98f66fb05f9" +dependencies = [ + "critical-section", + "riscv-pac", + "riscv-peripheral", + "vcell", +] + +[[package]] +name = "e310x" +version = "0.11.0" +source = "git+https://github.com/greenlsi/e310x.git#50536cc5be2fd6adf7f879f002fdd98f66fb05f9" +dependencies = [ + "riscv-pac", + "riscv-peripheral", + "vcell", +] + +[[package]] +name = "e310x-hal" +version = "0.11.0" +source = "git+https://github.com/greenlsi/e310x-hal.git?branch=master#931aea7ab142c1eb9eaadd4150946d8452229f27" +dependencies = [ + "e310x 0.11.0 (git+https://github.com/greenlsi/e310x.git?branch=master)", + "embedded-hal 0.2.7", + "nb 1.1.0", + "portable-atomic", + "riscv", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "hifive1" +version = "0.11.0" +source = "git+https://github.com/romancardenas/hifive1.git#ef8cea8b90bddb04509785d3e148ff145137520a" +dependencies = [ + "e310x-hal", + "embedded-hal 0.2.7", + "nb 1.1.0", + "riscv", +] + +[[package]] +name = "indexmap" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "riscv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f5c1b8bf41ea746266cdee443d1d1e9125c86ce1447e1a2615abd34330d33a9" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", +] + +[[package]] +name = "riscv-pac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18ceb4af23fdad434f938afdc35ce895a63d84f7333bb127d8065030848eb6a6" + +[[package]] +name = "riscv-peripheral" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07c799fe4e144bd4dd0c68fa33a41c1485f19730eea505d195124636e1253358" +dependencies = [ + "embedded-hal 1.0.0", + "riscv", + "riscv-pac", +] + +[[package]] +name = "riscv-rt" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0d35e32cf1383183e8885d8a9aa4402a087fd094dc34c2cb6df6687d0229dfe" +dependencies = [ + "riscv", + "riscv-rt-macros", +] + +[[package]] +name = "riscv-rt-macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8d100d466dbb76681ef6a9386f3da9abc570d57394e86da0ba5af8c4408486d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "riscv-slic" +version = "0.1.0" +source = "git+https://github.com/romancardenas/riscv-slic.git?rev=2a91edb#2a91edbff50bcc73169549923d278ff953d0986e" +dependencies = [ + "critical-section", + "heapless", + "riscv", + "riscv-slic-macros", +] + +[[package]] +name = "riscv-slic-macros" +version = "0.1.0" +source = "git+https://github.com/romancardenas/riscv-slic.git?rev=2a91edb#2a91edbff50bcc73169549923d278ff953d0986e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.49", +] + +[[package]] +name = "rtic" +version = "2.1.0" +dependencies = [ + "atomic-polyfill", + "bare-metal", + "critical-section", + "riscv", + "riscv-slic", + "rtic-core", + "rtic-macros", +] + +[[package]] +name = "rtic-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42" + +[[package]] +name = "rtic-macros" +version = "2.1.0" +dependencies = [ + "indexmap", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.49", +] + +[[package]] +name = "rtic_hifive1" +version = "0.1.0" +dependencies = [ + "e310x 0.11.0 (git+https://github.com/greenlsi/e310x.git)", + "heapless", + "hifive1", + "riscv", + "riscv-rt", + "rtic", + "semihosting", +] + +[[package]] +name = "semihosting" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab7a0be8d9e9893dfb5ce313aa0324396936d8bf788f5ef493c9f122ad84fd8" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/examples/hifive1/Cargo.toml b/examples/hifive1/Cargo.toml new file mode 100644 index 0000000..42d60a7 --- /dev/null +++ b/examples/hifive1/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "rtic_hifive1" +categories = ["embedded", "no-std"] +description = "Examples of RTIC apps for the HiFive1 board" +license = "MIT OR Apache-2.0" +version = "0.1.0" +edition = "2021" + +[workspace] + +[dependencies] +rtic = { path = "../../rtic" } +heapless = "0.8.0" +hifive1 = { git = "https://github.com/romancardenas/hifive1.git", features = ["board-redv"] } +e310x = { git = "https://github.com/greenlsi/e310x.git", features = ["rt"]} +riscv-rt = {version = "0.12.1", features = ["single-hart"]} +riscv = "0.11.0" +semihosting = { version = "0.1", features = ["stdio", "panic-handler"] } + +[features] +riscv-clint-backend = ["rtic/riscv-clint-backend"] +test-critical-section = [] diff --git a/examples/hifive1/examples/prio_inheritance.rs b/examples/hifive1/examples/prio_inheritance.rs new file mode 100644 index 0000000..5fc2399 --- /dev/null +++ b/examples/hifive1/examples/prio_inheritance.rs @@ -0,0 +1,140 @@ +#![no_main] +#![no_std] + +use riscv_rt as _; + +#[rtic::app(device = e310x, backend = HART0)] +mod app { + use core::{future::Future, pin::Pin, task::Context, task::Poll}; + use hifive1::hal::prelude::*; + use semihosting::{println, process::exit}; + + /// Dummy asynchronous function to showcase SW tasks + pub async fn yield_now(task: &str) { + /// Yield implementation + struct YieldNow { + yielded: bool, + } + println!(" [{}]: Yield", task); + + impl Future for YieldNow { + type Output = (); + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<()> { + if self.yielded { + return Poll::Ready(()); + } + + self.yielded = true; + cx.waker().wake_by_ref(); + + Poll::Pending + } + } + + YieldNow { yielded: false }.await + } + + #[shared] + struct Shared { + counter: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + // Pends the SoftLow interrupt but its handler won't run until *after* + // `init` returns because interrupts are disabled + let resources = unsafe { hifive1::hal::DeviceResources::steal() }; + let peripherals = resources.peripherals; + + let clocks = + hifive1::configure_clocks(peripherals.PRCI, peripherals.AONCLK, 64.mhz().into()); + let gpio = resources.pins; + + // Configure UART for stdout + hifive1::stdout::configure( + peripherals.UART0, + hifive1::pin!(gpio, uart0_tx), + hifive1::pin!(gpio, uart0_rx), + 115_200.bps(), + clocks, + ); + + (Shared { counter: 0 }, Local {}) + } + + #[idle(shared = [counter])] + fn idle(mut cx: idle::Context) -> ! { + println!("[Idle]: Started"); + // pend the medium priority SW task only once + soft_medium::spawn().unwrap(); + cx.shared.counter.lock(|counter| { + println!("[Idle]: Shared: {}", *counter); + }); + // exit QEMU simulator + println!("[Idle]: Finished"); + exit(0); + } + + /// Medium priority SW task. It is triggered by the idle and spawns the rest of the SW tasks + #[task(shared = [counter], priority = 2)] + async fn soft_medium(mut cx: soft_medium::Context) { + // Safe access to local `static mut` variable + println!(" [SoftMedium]: Started"); + cx.shared.counter.lock(|counter| { + // Spawn the other SW tasks INSIDE the critical section (just for showing priority inheritance) + soft_low_1::spawn().unwrap(); + soft_high::spawn().unwrap(); + soft_low_2::spawn().unwrap(); + + *counter += 1; + println!(" [SoftMedium]: Shared: {}", *counter); + }); + println!(" [SoftMedium]: Finished"); + } + + /// Low priority SW task. It runs cooperatively with soft_low_2 + #[task(shared = [counter], priority = 1)] + async fn soft_low_1(mut cx: soft_low_1::Context) { + println!(" [SoftLow1]: Started"); + cx.shared.counter.lock(|counter| { + *counter += 1; + println!(" [SoftLow1]: Shared: {}", *counter); + }); + // Yield to the other SW task + yield_now("SoftLow1").await; + + println!(" [SoftLow1]: Finished"); + } + + /// Low priority SW task. It runs cooperatively with soft_low_2 + #[task(shared = [counter], priority = 1)] + async fn soft_low_2(mut cx: soft_low_2::Context) { + println!(" [SoftLow2]: Started"); + cx.shared.counter.lock(|counter| { + *counter += 1; + println!(" [SoftLow2]: Shared: {}", *counter); + }); + + // Yield to the other SW task + yield_now("SoftLow2").await; + + println!(" [SoftLow2]: Finished"); + } + + /// High priority SW task + #[task(shared = [counter], priority = 3)] + async fn soft_high(mut cx: soft_high::Context) { + println!(" [SoftHigh]: Started"); + + cx.shared.counter.lock(|counter| { + *counter += 1; + println!(" [SoftHigh]: Shared: {}", counter); + }); + + println!(" [SoftHigh]: Finished"); + } +} diff --git a/examples/hifive1/examples/static.rs b/examples/hifive1/examples/static.rs new file mode 100644 index 0000000..34e71c6 --- /dev/null +++ b/examples/hifive1/examples/static.rs @@ -0,0 +1,60 @@ +//! zero priority task +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use hifive1 as _; +use riscv_rt as _; + +#[rtic::app(device = e310x, backend = HART0)] +mod app { + use semihosting::{process::exit, println}; + use heapless::spsc::{Consumer, Producer, Queue}; + + #[shared] + struct Shared {} + + #[local] + struct Local { + p: Producer<'static, u32, 5>, + c: Consumer<'static, u32, 5>, + } + + #[init(local = [q: Queue = Queue::new()])] + fn init(cx: init::Context) -> (Shared, Local) { + // q has 'static life-time so after the split and return of `init` + // it will continue to exist and be allocated + let (p, c) = cx.local.q.split(); + + foo::spawn().unwrap(); + + (Shared {}, Local { p, c }) + } + + #[idle(local = [c])] + fn idle(c: idle::Context) -> ! { + loop { + // Lock-free access to the same underlying queue! + if let Some(data) = c.local.c.dequeue() { + println!("received message: {}", data); + + // Run foo until data + if data == 3 { + exit(0); // Exit QEMU simulator + } else { + foo::spawn().unwrap(); + } + } + } + } + + #[task(local = [p, state: u32 = 0], priority = 1)] + async fn foo(c: foo::Context) { + *c.local.state += 1; + + // Lock-free access to the same underlying queue! + c.local.p.enqueue(*c.local.state).unwrap(); + } +} diff --git a/examples/hifive1/examples/task.rs b/examples/hifive1/examples/task.rs new file mode 100644 index 0000000..6968edb --- /dev/null +++ b/examples/hifive1/examples/task.rs @@ -0,0 +1,57 @@ +//! zero priority task +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use hifive1 as _; +use riscv_rt as _; + +#[rtic::app(device = e310x, backend = HART0)] +mod app { + use semihosting::{println, process::exit}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + + (Shared {}, Local {}) + } + + #[task] + async fn foo(_: foo::Context) { + println!("foo - start"); + + // spawns `bar` onto the task scheduler + // `foo` and `bar` have the same priority so `bar` will not run until + // after `foo` terminates + bar::spawn().unwrap(); + + println!("foo - middle"); + + // spawns `baz` onto the task scheduler + // `baz` has higher priority than `foo` so it immediately preempts `foo` + baz::spawn().unwrap(); + + println!("foo - end"); + } + + #[task] + async fn bar(_: bar::Context) { + println!("bar"); + + exit(0); // Exit QEMU simulator + } + + #[task(priority = 2)] + async fn baz(_: baz::Context) { + println!("baz"); + } +} diff --git a/examples/hifive1/examples/zero_prio_task.rs b/examples/hifive1/examples/zero_prio_task.rs new file mode 100644 index 0000000..2528c4f --- /dev/null +++ b/examples/hifive1/examples/zero_prio_task.rs @@ -0,0 +1,61 @@ +//! zero priority task +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use core::marker::PhantomData; +use hifive1 as _; +use riscv_rt as _; + +/// Does not impl send +pub struct NotSend { + _0: PhantomData<*const ()>, +} + +#[rtic::app(device = e310x, backend = HART0)] +mod app { + use super::NotSend; + use core::marker::PhantomData; + use semihosting::{println, process::exit}; + + #[shared] + struct Shared { + x: NotSend, + } + + #[local] + struct Local { + y: NotSend, + } + + #[init] + fn init(_cx: init::Context) -> (Shared, Local) { + println!("init"); + + async_task::spawn().unwrap(); + async_task2::spawn().unwrap(); + + ( + Shared { + x: NotSend { _0: PhantomData }, + }, + Local { + y: NotSend { _0: PhantomData }, + }, + ) + } + + #[task(priority = 0, shared = [x], local = [y])] + async fn async_task(_: async_task::Context) { + println!("hello from async"); + } + + #[task(priority = 0, shared = [x])] + async fn async_task2(_: async_task2::Context) { + println!("hello from async2"); + + exit(0); // Exit QEMU simulator + } +} diff --git a/examples/hifive1/rust-toolchain.toml b/examples/hifive1/rust-toolchain.toml new file mode 100644 index 0000000..3dc1c7e --- /dev/null +++ b/examples/hifive1/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "stable" +components = [ "rust-src", "rustfmt" ] +targets = [ "riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf" ] diff --git a/examples/lm3s6965/.cargo/config.toml b/examples/lm3s6965/.cargo/config.toml new file mode 100644 index 0000000..46b5177 --- /dev/null +++ b/examples/lm3s6965/.cargo/config.toml @@ -0,0 +1,13 @@ +[target.thumbv6m-none-eabi] +runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" + +[target.thumbv7m-none-eabi] +runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" + +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +rustflags = [ + "-C", "link-arg=-Tlink.x", +] + +[build] +target = "thumbv7m-none-eabi" diff --git a/examples/lm3s6965/Cargo.lock b/examples/lm3s6965/Cargo.lock new file mode 100644 index 0000000..696c606 --- /dev/null +++ b/examples/lm3s6965/Cargo.lock @@ -0,0 +1,527 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "atomic-polyfill" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" +dependencies = [ + "critical-section", +] + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bare-metal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal 0.2.5", + "bitfield", + "critical-section", + "embedded-hal 0.2.7", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "cortex-m-semihosting" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0" +dependencies = [ + "cortex-m", +] + +[[package]] +name = "critical-section" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216" + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-hal-bus" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57b4e6ede84339ebdb418cd986e6320a34b017cdf99b5cc3efceec6450b06886" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", + "embedded-hal-async", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fugit" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" +dependencies = [ + "gcd", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.49", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-core", + "futures-macro", + "futures-sink", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "lm3s6965" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d7ed5360fee8fd434cf7995ef1d7ad42697abb538e34383a39da8df5495446" +dependencies = [ + "cortex-m", + "cortex-m-rt", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "panic-semihosting" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8a3e1233d9073d76a870223512ce4eeea43c067a94a445c13bd6d792d7b1ab" +dependencies = [ + "cortex-m", + "cortex-m-semihosting", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rtic" +version = "2.1.0" +dependencies = [ + "atomic-polyfill", + "bare-metal 1.0.0", + "cortex-m", + "critical-section", + "rtic-core", + "rtic-macros", + "rtic-monotonics", +] + +[[package]] +name = "rtic-common" +version = "1.0.1" +dependencies = [ + "critical-section", + "portable-atomic", +] + +[[package]] +name = "rtic-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42" + +[[package]] +name = "rtic-macros" +version = "2.1.0" +dependencies = [ + "indexmap", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.49", +] + +[[package]] +name = "rtic-monotonics" +version = "1.5.0" +dependencies = [ + "atomic-polyfill", + "cfg-if", + "cortex-m", + "embedded-hal 1.0.0", + "fugit", + "rtic-time", +] + +[[package]] +name = "rtic-sync" +version = "1.3.0" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-hal-bus", + "heapless", + "portable-atomic", + "rtic-common", +] + +[[package]] +name = "rtic-time" +version = "1.3.0" +dependencies = [ + "critical-section", + "futures-util", + "rtic-common", +] + +[[package]] +name = "rtic_lm3s6965" +version = "0.1.0" +dependencies = [ + "bare-metal 1.0.0", + "cortex-m", + "cortex-m-semihosting", + "futures", + "heapless", + "lm3s6965", + "panic-semihosting", + "rtic", + "rtic-monotonics", + "rtic-sync", + "rtic-time", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +dependencies = [ + "vcell", +] diff --git a/examples/lm3s6965/Cargo.toml b/examples/lm3s6965/Cargo.toml new file mode 100644 index 0000000..86a7cbb --- /dev/null +++ b/examples/lm3s6965/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "rtic_lm3s6965" +categories = ["embedded", "no-std"] +description = "Examples of RTIC apps for the lm3s6965 chip" +license = "MIT OR Apache-2.0" +version = "0.1.0" +edition = "2021" + +[workspace] + +[dependencies] +heapless = "0.8" +lm3s6965 = "0.2" +cortex-m = "0.7.0" +bare-metal = "1.0.0" +cortex-m-semihosting = "0.5.0" +rtic-time = { path = "../../rtic-time" } +rtic-sync = { path = "../../rtic-sync" } +rtic-monotonics = { path = "../../rtic-monotonics", features = ["cortex-m-systick"] } +rtic = { path = "../../rtic" } + +[dependencies.futures] +version = "0.3.26" +default-features = false +features = ["async-await"] + +[dependencies.panic-semihosting] +features = ["exit"] +version = "0.6.0" + +[features] +test-critical-section = ["rtic/test-critical-section"] +thumbv6-backend = ["rtic/thumbv6-backend"] +thumbv7-backend = ["rtic/thumbv7-backend"] +thumbv8base-backend = ["rtic/thumbv8base-backend"] +thumbv8main-backend = ["rtic/thumbv8main-backend"] diff --git a/examples/lm3s6965/examples/async-channel-done.rs b/examples/lm3s6965/examples/async-channel-done.rs new file mode 100644 index 0000000..e9b9887 --- /dev/null +++ b/examples/lm3s6965/examples/async-channel-done.rs @@ -0,0 +1,65 @@ +//! examples/async-channel-done.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use rtic_sync::{channel::*, make_channel}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + const CAPACITY: usize = 1; + #[init] + fn init(_: init::Context) -> (Shared, Local) { + let (s, r) = make_channel!(u32, CAPACITY); + + receiver::spawn(r).unwrap(); + sender1::spawn(s.clone()).unwrap(); + sender2::spawn(s.clone()).unwrap(); + sender3::spawn(s).unwrap(); + + (Shared {}, Local {}) + } + + #[task] + async fn receiver(_c: receiver::Context, mut receiver: Receiver<'static, u32, CAPACITY>) { + while let Ok(val) = receiver.recv().await { + hprintln!("Receiver got: {}", val); + if val == 3 { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + } + } + + #[task] + async fn sender1(_c: sender1::Context, mut sender: Sender<'static, u32, CAPACITY>) { + hprintln!("Sender 1 sending: 1"); + sender.send(1).await.unwrap(); + hprintln!("Sender 1 done"); + } + + #[task] + async fn sender2(_c: sender2::Context, mut sender: Sender<'static, u32, CAPACITY>) { + hprintln!("Sender 2 sending: 2"); + sender.send(2).await.unwrap(); + hprintln!("Sender 2 done"); + } + + #[task] + async fn sender3(_c: sender3::Context, mut sender: Sender<'static, u32, CAPACITY>) { + hprintln!("Sender 3 sending: 3"); + sender.send(3).await.unwrap(); + hprintln!("Sender 3 done"); + } +} diff --git a/examples/lm3s6965/examples/async-channel-no-receiver.rs b/examples/lm3s6965/examples/async-channel-no-receiver.rs new file mode 100644 index 0000000..7e416be --- /dev/null +++ b/examples/lm3s6965/examples/async-channel-no-receiver.rs @@ -0,0 +1,37 @@ +//! examples/async-channel-no-receiver.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use rtic_sync::{channel::*, make_channel}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + const CAPACITY: usize = 1; + #[init] + fn init(_: init::Context) -> (Shared, Local) { + let (s, _r) = make_channel!(u32, CAPACITY); + + sender1::spawn(s.clone()).unwrap(); + + (Shared {}, Local {}) + } + + #[task] + async fn sender1(_c: sender1::Context, mut sender: Sender<'static, u32, CAPACITY>) { + hprintln!("Sender 1 sending: 1 {:?}", sender.send(1).await); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } +} diff --git a/examples/lm3s6965/examples/async-channel-no-sender.rs b/examples/lm3s6965/examples/async-channel-no-sender.rs new file mode 100644 index 0000000..c4f043c --- /dev/null +++ b/examples/lm3s6965/examples/async-channel-no-sender.rs @@ -0,0 +1,38 @@ +//! examples/async-channel-no-sender.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use rtic_sync::{channel::*, make_channel}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + const CAPACITY: usize = 1; + #[init] + fn init(_: init::Context) -> (Shared, Local) { + let (_s, r) = make_channel!(u32, CAPACITY); + + receiver::spawn(r).unwrap(); + + (Shared {}, Local {}) + } + + #[task] + async fn receiver(_c: receiver::Context, mut receiver: Receiver<'static, u32, CAPACITY>) { + hprintln!("Receiver got: {:?}", receiver.recv().await); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } +} diff --git a/examples/lm3s6965/examples/async-channel-try.rs b/examples/lm3s6965/examples/async-channel-try.rs new file mode 100644 index 0000000..92c6ab6 --- /dev/null +++ b/examples/lm3s6965/examples/async-channel-try.rs @@ -0,0 +1,56 @@ +//! examples/async-channel-try.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use rtic_sync::{channel::*, make_channel}; + + #[shared] + struct Shared {} + + #[local] + struct Local { + sender: Sender<'static, u32, CAPACITY>, + } + + const CAPACITY: usize = 1; + #[init] + fn init(_: init::Context) -> (Shared, Local) { + let (s, r) = make_channel!(u32, CAPACITY); + + receiver::spawn(r).unwrap(); + sender1::spawn(s.clone()).unwrap(); + + (Shared {}, Local { sender: s.clone() }) + } + + #[task] + async fn receiver(_c: receiver::Context, mut receiver: Receiver<'static, u32, CAPACITY>) { + while let Ok(val) = receiver.recv().await { + hprintln!("Receiver got: {}", val); + } + } + + #[task] + async fn sender1(_c: sender1::Context, mut sender: Sender<'static, u32, CAPACITY>) { + hprintln!("Sender 1 sending: 1"); + sender.send(1).await.unwrap(); + hprintln!("Sender 1 try sending: 2 {:?}", sender.try_send(2)); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + + // This interrupt is never triggered, but is used to demonstrate that + // one can (try to) send data into a channel from a hardware task. + #[task(binds = GPIOA, local = [sender])] + fn hw_task(cx: hw_task::Context) { + cx.local.sender.try_send(3).ok(); + } +} diff --git a/examples/lm3s6965/examples/async-channel.rs b/examples/lm3s6965/examples/async-channel.rs new file mode 100644 index 0000000..642e218 --- /dev/null +++ b/examples/lm3s6965/examples/async-channel.rs @@ -0,0 +1,62 @@ +//! examples/async-channel.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use rtic_sync::{channel::*, make_channel}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + const CAPACITY: usize = 5; + #[init] + fn init(_: init::Context) -> (Shared, Local) { + let (s, r) = make_channel!(u32, CAPACITY); + + receiver::spawn(r).unwrap(); + sender1::spawn(s.clone()).unwrap(); + sender2::spawn(s.clone()).unwrap(); + sender3::spawn(s).unwrap(); + + (Shared {}, Local {}) + } + + #[task] + async fn receiver(_c: receiver::Context, mut receiver: Receiver<'static, u32, CAPACITY>) { + while let Ok(val) = receiver.recv().await { + hprintln!("Receiver got: {}", val); + if val == 3 { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + } + } + + #[task] + async fn sender1(_c: sender1::Context, mut sender: Sender<'static, u32, CAPACITY>) { + hprintln!("Sender 1 sending: 1"); + sender.send(1).await.unwrap(); + } + + #[task] + async fn sender2(_c: sender2::Context, mut sender: Sender<'static, u32, CAPACITY>) { + hprintln!("Sender 2 sending: 2"); + sender.send(2).await.unwrap(); + } + + #[task] + async fn sender3(_c: sender3::Context, mut sender: Sender<'static, u32, CAPACITY>) { + hprintln!("Sender 3 sending: 3"); + sender.send(3).await.unwrap(); + } +} diff --git a/examples/lm3s6965/examples/async-delay.rs b/examples/lm3s6965/examples/async-delay.rs new file mode 100644 index 0000000..9ccfc02 --- /dev/null +++ b/examples/lm3s6965/examples/async-delay.rs @@ -0,0 +1,58 @@ +//! examples/async-delay.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use rtic_monotonics::systick::*; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(cx: init::Context) -> (Shared, Local) { + hprintln!("init"); + + let systick_token = rtic_monotonics::create_systick_token!(); + Systick::start(cx.core.SYST, 12_000_000, systick_token); + + foo::spawn().ok(); + bar::spawn().ok(); + baz::spawn().ok(); + + (Shared {}, Local {}) + } + + #[task] + async fn foo(_cx: foo::Context) { + hprintln!("hello from foo"); + Systick::delay(100.millis()).await; + hprintln!("bye from foo"); + } + + #[task] + async fn bar(_cx: bar::Context) { + hprintln!("hello from bar"); + Systick::delay(200.millis()).await; + hprintln!("bye from bar"); + } + + #[task] + async fn baz(_cx: baz::Context) { + hprintln!("hello from baz"); + Systick::delay(300.millis()).await; + hprintln!("bye from baz"); + + debug::exit(debug::EXIT_SUCCESS); + } +} diff --git a/examples/lm3s6965/examples/async-task-multiple-prios.rs b/examples/lm3s6965/examples/async-task-multiple-prios.rs new file mode 100644 index 0000000..39b6d60 --- /dev/null +++ b/examples/lm3s6965/examples/async-task-multiple-prios.rs @@ -0,0 +1,93 @@ +//! examples/async-task-multiple-prios.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +// NOTES: +// +// - Async tasks cannot have `#[lock_free]` resources, as they can interleave and each async +// task can have a mutable reference stored. +// - Spawning an async task equates to it being polled once. + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared { + a: u32, + b: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + hprintln!("init"); + + async_task1::spawn(1).ok(); + async_task2::spawn().ok(); + async_task3::spawn().ok(); + async_task4::spawn().ok(); + + (Shared { a: 0, b: 0 }, Local {}) + } + + #[idle] + fn idle(_: idle::Context) -> ! { + loop { + hprintln!("idle"); + debug::exit(debug::EXIT_SUCCESS); + } + } + + #[task(priority = 1, shared = [a, b])] + async fn async_task1(mut cx: async_task1::Context, inc: u32) { + hprintln!( + "hello from async 1 a {}", + cx.shared.a.lock(|a| { + *a += inc; + *a + }) + ); + } + + #[task(priority = 1, shared = [a, b])] + async fn async_task2(mut cx: async_task2::Context) { + hprintln!( + "hello from async 2 a {}", + cx.shared.a.lock(|a| { + *a += 1; + *a + }) + ); + } + + #[task(priority = 2, shared = [a, b])] + async fn async_task3(mut cx: async_task3::Context) { + hprintln!( + "hello from async 3 a {}", + cx.shared.a.lock(|a| { + *a += 1; + *a + }) + ); + } + + #[task(priority = 2, shared = [a, b])] + async fn async_task4(mut cx: async_task4::Context) { + hprintln!( + "hello from async 4 a {}", + cx.shared.a.lock(|a| { + *a += 1; + *a + }) + ); + } +} diff --git a/examples/lm3s6965/examples/async-task.rs b/examples/lm3s6965/examples/async-task.rs new file mode 100644 index 0000000..1867c4d --- /dev/null +++ b/examples/lm3s6965/examples/async-task.rs @@ -0,0 +1,71 @@ +//! examples/async-task.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +// NOTES: +// +// - Async tasks cannot have `#[lock_free]` resources, as they can interleave and each async +// task can have a mutable reference stored. +// - Spawning an async task equates to it being polled once. + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared { + a: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_cx: init::Context) -> (Shared, Local) { + hprintln!("init"); + + async_task::spawn().unwrap(); + async_task_args::spawn(1, 2).unwrap(); + async_task2::spawn().unwrap(); + + (Shared { a: 0 }, Local {}) + } + + #[idle(shared = [a])] + fn idle(_: idle::Context) -> ! { + loop { + hprintln!("idle"); + debug::exit(debug::EXIT_SUCCESS); + cortex_m::asm::wfi(); // put the MCU in sleep mode until interrupt occurs + } + } + + #[task(binds = UART1, shared = [a])] + fn hw_task(cx: hw_task::Context) { + let hw_task::SharedResources { a: _, .. } = cx.shared; + hprintln!("hello from hw"); + } + + #[task(shared = [a], priority = 1)] + async fn async_task(cx: async_task::Context) { + let async_task::SharedResources { a: _, .. } = cx.shared; + hprintln!("hello from async"); + } + + #[task(priority = 1)] + async fn async_task_args(_cx: async_task_args::Context, a: u32, b: i32) { + hprintln!("hello from async with args a: {}, b: {}", a, b); + } + + #[task(priority = 2, shared = [a])] + async fn async_task2(cx: async_task2::Context) { + let async_task2::SharedResources { a: _, .. } = cx.shared; + hprintln!("hello from async2"); + } +} diff --git a/examples/lm3s6965/examples/async-timeout.rs b/examples/lm3s6965/examples/async-timeout.rs new file mode 100644 index 0000000..e5e129f --- /dev/null +++ b/examples/lm3s6965/examples/async-timeout.rs @@ -0,0 +1,96 @@ +//! examples/async-timeout.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use cortex_m_semihosting::{debug, hprintln}; +use panic_semihosting as _; +use rtic_monotonics::systick::*; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)] +mod app { + use super::*; + use futures::{future::FutureExt, select_biased}; + use rtic_monotonics::Monotonic; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + // ANCHOR: init + #[init] + fn init(cx: init::Context) -> (Shared, Local) { + hprintln!("init"); + + let systick_token = rtic_monotonics::create_systick_token!(); + Systick::start(cx.core.SYST, 12_000_000, systick_token); + // ANCHOR_END: init + + foo::spawn().ok(); + + (Shared {}, Local {}) + } + + #[task] + async fn foo(_cx: foo::Context) { + // ANCHOR: select_biased + // Call hal with short relative timeout using `select_biased` + select_biased! { + v = hal_get(1).fuse() => hprintln!("hal returned {}", v), + _ = Systick::delay(200.millis()).fuse() => hprintln!("timeout", ), // this will finish first + } + + // Call hal with long relative timeout using `select_biased` + select_biased! { + v = hal_get(1).fuse() => hprintln!("hal returned {}", v), // hal finish first + _ = Systick::delay(1000.millis()).fuse() => hprintln!("timeout", ), + } + // ANCHOR_END: select_biased + + // ANCHOR: timeout_after_basic + // Call hal with long relative timeout using monotonic `timeout_after` + match Systick::timeout_after(1000.millis(), hal_get(1)).await { + Ok(v) => hprintln!("hal returned {}", v), + _ => hprintln!("timeout"), + } + // ANCHOR_END: timeout_after_basic + + // ANCHOR: timeout_at_basic + // get the current time instance + let mut instant = Systick::now(); + + // do this 3 times + for n in 0..3 { + // absolute point in time without drift + instant += 1000.millis(); + Systick::delay_until(instant).await; + + // absolute point in time for timeout + let timeout = instant + 500.millis(); + hprintln!("now is {:?}, timeout at {:?}", Systick::now(), timeout); + + match Systick::timeout_at(timeout, hal_get(n)).await { + Ok(v) => hprintln!("hal returned {} at time {:?}", v, Systick::now()), + _ => hprintln!("timeout"), + } + } + // ANCHOR_END: timeout_at_basic + + debug::exit(debug::EXIT_SUCCESS); + } +} + +// Emulate some hal +async fn hal_get(n: u32) -> u32 { + // emulate some delay time dependent on n + let d = 350.millis() + n * 100.millis(); + hprintln!("the hal takes a duration of {:?}", d); + Systick::delay(d).await; + // emulate some return value + 5 +} diff --git a/examples/lm3s6965/examples/big-struct-opt.rs b/examples/lm3s6965/examples/big-struct-opt.rs new file mode 100644 index 0000000..109cc5d --- /dev/null +++ b/examples/lm3s6965/examples/big-struct-opt.rs @@ -0,0 +1,80 @@ +//! examples/big-struct-opt.rs +//! +//! Example on how to initialize a large struct without needing to copy it via `LateResources`, +//! effectively saving stack space needed for the copies. + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +/// Some big struct +pub struct BigStruct { + /// Big content + pub data: [u8; 2048], +} + +impl BigStruct { + fn new() -> Self { + BigStruct { data: [22; 2048] } + } +} + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use super::BigStruct; + use core::mem::MaybeUninit; + use cortex_m_semihosting::{debug, hprintln}; + use lm3s6965::Interrupt; + + #[shared] + struct Shared { + big_struct: &'static mut BigStruct, + } + + #[local] + struct Local {} + + #[init(local = [bs: MaybeUninit = MaybeUninit::uninit()])] + fn init(cx: init::Context) -> (Shared, Local) { + let big_struct = unsafe { + // write directly into the static storage + cx.local.bs.as_mut_ptr().write(BigStruct::new()); + &mut *cx.local.bs.as_mut_ptr() + }; + + rtic::pend(Interrupt::UART0); + async_task::spawn().unwrap(); + ( + Shared { + // assign the reference so we can use the resource + big_struct, + }, + Local {}, + ) + } + + #[idle] + fn idle(_: idle::Context) -> ! { + loop { + hprintln!("idle"); + debug::exit(debug::EXIT_SUCCESS); + } + } + + #[task(binds = UART0, shared = [big_struct])] + fn uart0(mut cx: uart0::Context) { + cx.shared + .big_struct + .lock(|b| hprintln!("uart0 data:{:?}", &b.data[0..5])); + } + + #[task(shared = [big_struct], priority = 2)] + async fn async_task(mut cx: async_task::Context) { + cx.shared + .big_struct + .lock(|b| hprintln!("async_task data:{:?}", &b.data[0..5])); + } +} diff --git a/examples/lm3s6965/examples/binds.rs b/examples/lm3s6965/examples/binds.rs new file mode 100644 index 0000000..b101d54 --- /dev/null +++ b/examples/lm3s6965/examples/binds.rs @@ -0,0 +1,54 @@ +//! examples/binds.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +// `examples/interrupt.rs` rewritten to use `binds` +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use lm3s6965::Interrupt; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + rtic::pend(Interrupt::UART0); + + hprintln!("init"); + + (Shared {}, Local {}) + } + + #[idle] + fn idle(_: idle::Context) -> ! { + hprintln!("idle"); + + rtic::pend(Interrupt::UART0); + + loop { + cortex_m::asm::nop(); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + } + + #[task(binds = UART0, local = [times: u32 = 0])] + fn foo(cx: foo::Context) { + *cx.local.times += 1; + + hprintln!( + "foo called {} time{}", + *cx.local.times, + if *cx.local.times > 1 { "s" } else { "" } + ); + } +} diff --git a/examples/lm3s6965/examples/common.rs b/examples/lm3s6965/examples/common.rs new file mode 100644 index 0000000..7f68739 --- /dev/null +++ b/examples/lm3s6965/examples/common.rs @@ -0,0 +1,86 @@ +//! examples/common.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [UART0, UART1])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local { + local_to_foo: i64, + local_to_bar: i64, + local_to_idle: i64, + } + + // `#[init]` cannot access locals from the `#[local]` struct as they are initialized here. + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + bar::spawn().unwrap(); + + ( + Shared {}, + // initial values for the `#[local]` resources + Local { + local_to_foo: 0, + local_to_bar: 0, + local_to_idle: 0, + }, + ) + } + + // `local_to_idle` can only be accessed from this context + #[idle(local = [local_to_idle])] + fn idle(cx: idle::Context) -> ! { + let local_to_idle = cx.local.local_to_idle; + *local_to_idle += 1; + + hprintln!("idle: local_to_idle = {}", local_to_idle); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + + // error: no `local_to_foo` field in `idle::LocalResources` + // _cx.local.local_to_foo += 1; + + // error: no `local_to_bar` field in `idle::LocalResources` + // _cx.local.local_to_bar += 1; + + loop { + cortex_m::asm::nop(); + } + } + + // `local_to_foo` can only be accessed from this context + #[task(local = [local_to_foo], priority = 1)] + async fn foo(cx: foo::Context) { + let local_to_foo = cx.local.local_to_foo; + *local_to_foo += 1; + + // error: no `local_to_bar` field in `foo::LocalResources` + // cx.local.local_to_bar += 1; + + hprintln!("foo: local_to_foo = {}", local_to_foo); + } + + // `local_to_bar` can only be accessed from this context + #[task(local = [local_to_bar], priority = 1)] + async fn bar(cx: bar::Context) { + let local_to_bar = cx.local.local_to_bar; + *local_to_bar += 1; + + // error: no `local_to_foo` field in `bar::LocalResources` + // cx.local.local_to_foo += 1; + + hprintln!("bar: local_to_bar = {}", local_to_bar); + } +} diff --git a/examples/lm3s6965/examples/complex.rs b/examples/lm3s6965/examples/complex.rs new file mode 100644 index 0000000..a4fe659 --- /dev/null +++ b/examples/lm3s6965/examples/complex.rs @@ -0,0 +1,129 @@ +//! examples/complex.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + + use cortex_m_semihosting::{debug, hprintln}; + use lm3s6965::Interrupt; + + #[shared] + struct Shared { + s2: u32, // shared with ceiling 2 + s3: u32, // shared with ceiling 3 + s4: u32, // shared with ceiling 4 + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + hprintln!("init"); + + ( + Shared { + s2: 0, + s3: 0, + s4: 0, + }, + Local {}, + ) + } + + #[idle(shared = [s2, s3])] + fn idle(mut cx: idle::Context) -> ! { + hprintln!("idle p0 started"); + rtic::pend(Interrupt::GPIOC); + cx.shared.s3.lock(|s| { + hprintln!("idle enter lock s3 {}", s); + hprintln!("idle pend t0"); + rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 3 + hprintln!("idle pend t1"); + rtic::pend(Interrupt::GPIOB); // t1 p3, with shared ceiling 3 + hprintln!("idle pend t2"); + rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing + hprintln!("idle still in lock s3 {}", s); + }); + hprintln!("\nback in idle"); + + cx.shared.s2.lock(|s| { + hprintln!("enter lock s2 {}", s); + hprintln!("idle pend t0"); + rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 2 + hprintln!("idle pend t1"); + rtic::pend(Interrupt::GPIOB); // t1 p3, no sharing + hprintln!("idle pend t2"); + rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing + hprintln!("idle still in lock s2 {}", s); + }); + hprintln!("\nidle exit"); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + + loop { + cortex_m::asm::nop(); + } + } + + #[task(binds = GPIOA, priority = 2, local = [times: u32 = 0], shared = [s2, s3])] + fn t0(cx: t0::Context) { + // Safe access to local `static mut` variable + *cx.local.times += 1; + + hprintln!( + "t0 p2 called {} time{}", + *cx.local.times, + if *cx.local.times > 1 { "s" } else { "" } + ); + hprintln!("t0 p2 exit"); + } + + #[task(binds = GPIOB, priority = 3, local = [times: u32 = 0], shared = [s3, s4])] + fn t1(mut cx: t1::Context) { + // Safe access to local `static mut` variable + *cx.local.times += 1; + + hprintln!( + "t1 p3 called {} time{}", + *cx.local.times, + if *cx.local.times > 1 { "s" } else { "" } + ); + + cx.shared.s4.lock(|s| { + hprintln!("t1 enter lock s4 {}", s); + hprintln!("t1 pend t0"); + rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 2 + hprintln!("t1 pend t2"); + rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing + hprintln!("t1 still in lock s4 {}", s); + }); + + hprintln!("t1 p3 exit"); + } + + #[task(binds = GPIOC, priority = 4, local = [times: u32 = 0], shared = [s4])] + fn t2(mut cx: t2::Context) { + // Safe access to local `static mut` variable + *cx.local.times += 1; + + hprintln!( + "t2 p4 called {} time{}", + *cx.local.times, + if *cx.local.times > 1 { "s" } else { "" } + ); + + cx.shared.s4.lock(|s| { + hprintln!("enter lock s4 {}", s); + *s += 1; + }); + hprintln!("t3 p4 exit"); + } +} diff --git a/examples/lm3s6965/examples/declared_locals.rs b/examples/lm3s6965/examples/declared_locals.rs new file mode 100644 index 0000000..b1bb9f4 --- /dev/null +++ b/examples/lm3s6965/examples/declared_locals.rs @@ -0,0 +1,47 @@ +//! examples/declared_locals.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::debug; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init(local = [a: u32 = 0])] + fn init(cx: init::Context) -> (Shared, Local) { + // Locals in `#[init]` have 'static lifetime + let _a: &'static mut u32 = cx.local.a; + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + + (Shared {}, Local {}) + } + + #[idle(local = [a: u32 = 0])] + fn idle(cx: idle::Context) -> ! { + // Locals in `#[idle]` have 'static lifetime + let _a: &'static mut u32 = cx.local.a; + + loop {} + } + + #[task(binds = UART0, local = [a: u32 = 0])] + fn foo(cx: foo::Context) { + // Locals in `#[task]`s have a local lifetime + let _a: &mut u32 = cx.local.a; + + // error: explicit lifetime required in the type of `cx` + // let _a: &'static mut u32 = cx.local.a; + } +} diff --git a/examples/lm3s6965/examples/destructure.rs b/examples/lm3s6965/examples/destructure.rs new file mode 100644 index 0000000..ac35187 --- /dev/null +++ b/examples/lm3s6965/examples/destructure.rs @@ -0,0 +1,56 @@ +//! examples/destructure.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [UART0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared { + a: u32, + b: u32, + c: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + bar::spawn().unwrap(); + + (Shared { a: 0, b: 1, c: 2 }, Local {}) + } + + #[idle] + fn idle(_: idle::Context) -> ! { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + loop {} + } + + // Direct destructure + #[task(shared = [&a, &b, &c], priority = 1)] + async fn foo(cx: foo::Context) { + let a = cx.shared.a; + let b = cx.shared.b; + let c = cx.shared.c; + + hprintln!("foo: a = {}, b = {}, c = {}", a, b, c); + } + + // De-structure-ing syntax + #[task(shared = [&a, &b, &c], priority = 1)] + async fn bar(cx: bar::Context) { + let bar::SharedResources { a, b, c, .. } = cx.shared; + + hprintln!("bar: a = {}, b = {}, c = {}", a, b, c); + } +} diff --git a/examples/lm3s6965/examples/executor-size.rs b/examples/lm3s6965/examples/executor-size.rs new file mode 100644 index 0000000..d825729 --- /dev/null +++ b/examples/lm3s6965/examples/executor-size.rs @@ -0,0 +1,42 @@ +//! examples/executor-size.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(cx: init::Context) -> (Shared, Local) { + hprintln!("init, total executor size = {}", cx.executors_size); + + foo::spawn().ok(); + bar::spawn().ok(); + baz::spawn().ok(); + + (Shared {}, Local {}) + } + + #[task] + async fn foo(_cx: foo::Context) {} + + #[task] + async fn bar(_cx: bar::Context) {} + + #[task] + async fn baz(_cx: baz::Context) { + debug::exit(debug::EXIT_SUCCESS); + } +} diff --git a/examples/lm3s6965/examples/extern_binds.rs b/examples/lm3s6965/examples/extern_binds.rs new file mode 100644 index 0000000..45939d2 --- /dev/null +++ b/examples/lm3s6965/examples/extern_binds.rs @@ -0,0 +1,59 @@ +//! examples/extern_binds.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use cortex_m_semihosting::{debug, hprintln}; +use lm3s6965::Interrupt; +use panic_semihosting as _; + +// Free function implementing `init`. +fn init(_: app::init::Context) -> (app::Shared, app::Local) { + rtic::pend(Interrupt::UART0); + + hprintln!("init"); + + (app::Shared {}, app::Local {}) +} + +// Free function implementing `idle`. +fn idle(_: app::idle::Context) -> ! { + hprintln!("idle"); + + rtic::pend(Interrupt::UART0); + + loop { + cortex_m::asm::nop(); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } +} + +// Free function implementing the interrupt bound task `foo`. +fn foo(_: app::foo::Context) { + hprintln!("foo called"); +} + +#[rtic::app(device = lm3s6965)] +mod app { + use crate::{foo, idle, init}; + + #[shared] + pub struct Shared {} + + #[local] + pub struct Local {} + + extern "Rust" { + #[init] + fn init(_: init::Context) -> (Shared, Local); + + #[idle] + fn idle(_: idle::Context) -> !; + + #[task(binds = UART0)] + fn foo(_: foo::Context); + } +} diff --git a/examples/lm3s6965/examples/extern_spawn.rs b/examples/lm3s6965/examples/extern_spawn.rs new file mode 100644 index 0000000..7f68b42 --- /dev/null +++ b/examples/lm3s6965/examples/extern_spawn.rs @@ -0,0 +1,40 @@ +//! examples/extern_spawn.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use cortex_m_semihosting::{debug, hprintln}; +use panic_semihosting as _; + +// Free function implementing the spawnable task `foo`. +// Notice, you need to indicate an anonymous lifetime <'a_> +async fn foo(_c: app::foo::Context<'_>) { + hprintln!("foo"); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator +} + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use crate::foo; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + + (Shared {}, Local {}) + } + + extern "Rust" { + #[task()] + async fn foo(_c: foo::Context); + } +} diff --git a/examples/lm3s6965/examples/generics.rs b/examples/lm3s6965/examples/generics.rs new file mode 100644 index 0000000..dd042a3 --- /dev/null +++ b/examples/lm3s6965/examples/generics.rs @@ -0,0 +1,67 @@ +//! examples/generics.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use cortex_m_semihosting::hprintln; +use panic_semihosting as _; +use rtic::Mutex; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use lm3s6965::Interrupt; + + #[shared] + struct Shared { + shared: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + rtic::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART1); + + (Shared { shared: 0 }, Local {}) + } + + #[task(binds = UART0, shared = [shared], local = [state: u32 = 0])] + fn uart0(c: uart0::Context) { + hprintln!("UART0(STATE = {})", *c.local.state); + + // second argument has type `shared::shared` + super::advance(c.local.state, c.shared.shared); + + rtic::pend(Interrupt::UART1); + + cortex_m::asm::nop(); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + + #[task(binds = UART1, priority = 2, shared = [shared], local = [state: u32 = 0])] + fn uart1(c: uart1::Context) { + hprintln!("UART1(STATE = {})", *c.local.state); + + // second argument has type `shared::shared` + super::advance(c.local.state, c.shared.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) { + *state += 1; + + let (old, new) = shared.lock(|shared: &mut u32| { + let old = *shared; + *shared += *state; + (old, *shared) + }); + + hprintln!("shared: {} -> {}", old, new); +} diff --git a/examples/lm3s6965/examples/hardware.rs b/examples/lm3s6965/examples/hardware.rs new file mode 100644 index 0000000..3bd62b6 --- /dev/null +++ b/examples/lm3s6965/examples/hardware.rs @@ -0,0 +1,60 @@ +//! examples/hardware.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use lm3s6965::Interrupt; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + // 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"); + + (Shared {}, Local {}) + } + + #[idle] + fn idle(_: idle::Context) -> ! { + // interrupts are enabled again; the `UART0` handler runs at this point + + hprintln!("idle"); + + // Some backends provide a manual way of pending an + // interrupt. + rtic::pend(Interrupt::UART0); + + loop { + cortex_m::asm::nop(); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + } + + #[task(binds = UART0, local = [times: u32 = 0])] + fn uart0(cx: uart0::Context) { + // Safe access to local `static mut` variable + *cx.local.times += 1; + + hprintln!( + "UART0 called {} time{}", + *cx.local.times, + if *cx.local.times > 1 { "s" } else { "" } + ); + } +} diff --git a/examples/lm3s6965/examples/idle-wfi.rs b/examples/lm3s6965/examples/idle-wfi.rs new file mode 100644 index 0000000..72aaa95 --- /dev/null +++ b/examples/lm3s6965/examples/idle-wfi.rs @@ -0,0 +1,48 @@ +//! examples/idle-wfi.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(mut cx: init::Context) -> (Shared, Local) { + hprintln!("init"); + + // Set the ARM SLEEPONEXIT bit to go to sleep after handling interrupts + // See https://developer.arm.com/docs/100737/0100/power-management/sleep-mode/sleep-on-exit-bit + cx.core.SCB.set_sleepdeep(); + + (Shared {}, Local {}) + } + + #[idle(local = [x: u32 = 0])] + fn idle(cx: idle::Context) -> ! { + // Locals in idle have lifetime 'static + let _x: &'static mut u32 = cx.local.x; + + hprintln!("idle"); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + + loop { + // Now Wait For Interrupt is used instead of a busy-wait loop + // to allow MCU to sleep between interrupts + // https://developer.arm.com/documentation/ddi0406/c/Application-Level-Architecture/Instruction-Details/Alphabetical-list-of-instructions/WFI + rtic::export::wfi() + } + } +} diff --git a/examples/lm3s6965/examples/idle.rs b/examples/lm3s6965/examples/idle.rs new file mode 100644 index 0000000..4149818 --- /dev/null +++ b/examples/lm3s6965/examples/idle.rs @@ -0,0 +1,41 @@ +//! examples/idle.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + hprintln!("init"); + + (Shared {}, Local {}) + } + + #[idle(local = [x: u32 = 0])] + fn idle(cx: idle::Context) -> ! { + // Locals in idle have lifetime 'static + let _x: &'static mut u32 = cx.local.x; + + hprintln!("idle"); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + + loop { + cortex_m::asm::nop(); + } + } +} diff --git a/examples/lm3s6965/examples/init.rs b/examples/lm3s6965/examples/init.rs new file mode 100644 index 0000000..634d309 --- /dev/null +++ b/examples/lm3s6965/examples/init.rs @@ -0,0 +1,42 @@ +//! examples/init.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, peripherals = true)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init(local = [x: u32 = 0])] + fn init(cx: init::Context) -> (Shared, Local) { + // Cortex-M peripherals + let _core: cortex_m::Peripherals = cx.core; + + // Device specific peripherals + let _device: lm3s6965::Peripherals = cx.device; + + // Locals in `init` have 'static lifetime + let _x: &'static mut u32 = cx.local.x; + + // Access to the critical section token, + // to indicate that this is a critical section + let _cs_token: bare_metal::CriticalSection = cx.cs; + + hprintln!("init"); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + + (Shared {}, Local {}) + } +} diff --git a/examples/lm3s6965/examples/locals.rs b/examples/lm3s6965/examples/locals.rs new file mode 100644 index 0000000..5d5e246 --- /dev/null +++ b/examples/lm3s6965/examples/locals.rs @@ -0,0 +1,86 @@ +//! examples/locals.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [UART0, UART1])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local { + local_to_foo: i64, + local_to_bar: i64, + local_to_idle: i64, + } + + // `#[init]` cannot access locals from the `#[local]` struct as they are initialized here. + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + bar::spawn().unwrap(); + + ( + Shared {}, + // initial values for the `#[local]` resources + Local { + local_to_foo: 0, + local_to_bar: 0, + local_to_idle: 0, + }, + ) + } + + // `local_to_idle` can only be accessed from this context + #[idle(local = [local_to_idle])] + fn idle(cx: idle::Context) -> ! { + let local_to_idle = cx.local.local_to_idle; + *local_to_idle += 1; + + hprintln!("idle: local_to_idle = {}", local_to_idle); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + + // error: no `local_to_foo` field in `idle::LocalResources` + // _cx.local.local_to_foo += 1; + + // error: no `local_to_bar` field in `idle::LocalResources` + // _cx.local.local_to_bar += 1; + + loop { + cortex_m::asm::nop(); + } + } + + // `local_to_foo` can only be accessed from this context + #[task(local = [local_to_foo], priority = 1)] + async fn foo(cx: foo::Context) { + let local_to_foo = cx.local.local_to_foo; + *local_to_foo += 1; + + // error: no `local_to_bar` field in `foo::LocalResources` + // cx.local.local_to_bar += 1; + + hprintln!("foo: local_to_foo = {}", local_to_foo); + } + + // `local_to_bar` can only be accessed from this context + #[task(local = [local_to_bar], priority = 1)] + async fn bar(cx: bar::Context) { + let local_to_bar = cx.local.local_to_bar; + *local_to_bar += 1; + + // error: no `local_to_foo` field in `bar::LocalResources` + // cx.local.local_to_foo += 1; + + hprintln!("bar: local_to_bar = {}", local_to_bar); + } +} diff --git a/examples/lm3s6965/examples/lock-free.rs b/examples/lm3s6965/examples/lock-free.rs new file mode 100644 index 0000000..c9d2ab0 --- /dev/null +++ b/examples/lm3s6965/examples/lock-free.rs @@ -0,0 +1,50 @@ +//! examples/lock-free.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use lm3s6965::Interrupt; + + #[shared] + struct Shared { + #[lock_free] // <- lock-free shared resource + counter: u64, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + rtic::pend(Interrupt::UART0); + + (Shared { counter: 0 }, Local {}) + } + + #[task(binds = UART0, shared = [counter])] // <- same priority + fn foo(c: foo::Context) { + rtic::pend(Interrupt::UART1); + + *c.shared.counter += 1; // <- no lock API required + let counter = *c.shared.counter; + hprintln!(" foo = {}", counter); + } + + #[task(binds = UART1, shared = [counter])] // <- same priority + fn bar(c: bar::Context) { + rtic::pend(Interrupt::UART0); + *c.shared.counter += 1; // <- no lock API required + let counter = *c.shared.counter; + hprintln!(" bar = {}", counter); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } +} diff --git a/examples/lm3s6965/examples/lock.rs b/examples/lm3s6965/examples/lock.rs new file mode 100644 index 0000000..091a1b0 --- /dev/null +++ b/examples/lm3s6965/examples/lock.rs @@ -0,0 +1,72 @@ +//! examples/lock.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [GPIOA, GPIOB, GPIOC])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared { + shared: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + + (Shared { shared: 0 }, Local {}) + } + + // when omitted priority is assumed to be `1` + #[task(shared = [shared])] + async fn foo(mut c: foo::Context) { + hprintln!("A"); + + // the lower priority task requires a critical section to access the data + c.shared.shared.lock(|shared| { + // data can only be modified within this critical section (closure) + *shared += 1; + + // bar will *not* run right now due to the critical section + bar::spawn().unwrap(); + + hprintln!("B - shared = {}", *shared); + + // baz does not contend for `shared` so it's allowed to run now + baz::spawn().unwrap(); + }); + + // critical section is over: bar can now start + + hprintln!("E"); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + + #[task(priority = 2, shared = [shared])] + async fn bar(mut c: bar::Context) { + // the higher priority task does still need a critical section + let shared = c.shared.shared.lock(|shared| { + *shared += 1; + + *shared + }); + + hprintln!("D - shared = {}", shared); + } + + #[task(priority = 3)] + async fn baz(_: baz::Context) { + hprintln!("C"); + } +} diff --git a/examples/lm3s6965/examples/multilock.rs b/examples/lm3s6965/examples/multilock.rs new file mode 100644 index 0000000..77245ae --- /dev/null +++ b/examples/lm3s6965/examples/multilock.rs @@ -0,0 +1,56 @@ +//! examples/mutlilock.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared { + shared1: u32, + shared2: u32, + shared3: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + locks::spawn().unwrap(); + + ( + Shared { + shared1: 0, + shared2: 0, + shared3: 0, + }, + Local {}, + ) + } + + // when omitted priority is assumed to be `1` + #[task(shared = [shared1, shared2, shared3])] + async fn locks(c: locks::Context) { + let s1 = c.shared.shared1; + let s2 = c.shared.shared2; + let s3 = c.shared.shared3; + + (s1, s2, s3).lock(|s1, s2, s3| { + *s1 += 1; + *s2 += 1; + *s3 += 1; + + hprintln!("Multiple locks, s1: {}, s2: {}, s3: {}", *s1, *s2, *s3); + }); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } +} diff --git a/examples/lm3s6965/examples/not-sync.rs b/examples/lm3s6965/examples/not-sync.rs new file mode 100644 index 0000000..09ba77e --- /dev/null +++ b/examples/lm3s6965/examples/not-sync.rs @@ -0,0 +1,67 @@ +//! `examples/not-sync.rs` + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(missing_docs)] + +use core::marker::PhantomData; +use panic_semihosting as _; + +/// Not sync +pub struct NotSync { + _0: PhantomData<*const ()>, + data: u32, +} + +unsafe impl Send for NotSync {} + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use super::NotSync; + use core::marker::PhantomData; + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared { + shared: NotSync, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + hprintln!("init"); + + foo::spawn().unwrap(); + bar::spawn().unwrap(); + ( + Shared { + shared: NotSync { + _0: PhantomData, + data: 13, + }, + }, + Local {}, + ) + } + + #[idle] + fn idle(_: idle::Context) -> ! { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + loop {} + } + + #[task(shared = [&shared], priority = 1)] + async fn foo(c: foo::Context) { + let shared: &NotSync = c.shared.shared; + hprintln!("foo a {}", shared.data); + } + + #[task(shared = [&shared], priority = 1)] + async fn bar(c: bar::Context) { + let shared: &NotSync = c.shared.shared; + hprintln!("bar a {}", shared.data); + } +} diff --git a/examples/lm3s6965/examples/only-shared-access.rs b/examples/lm3s6965/examples/only-shared-access.rs new file mode 100644 index 0000000..c83dca5 --- /dev/null +++ b/examples/lm3s6965/examples/only-shared-access.rs @@ -0,0 +1,43 @@ +//! examples/only-shared-access.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [UART0, UART1])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared { + key: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + bar::spawn().unwrap(); + + (Shared { key: 0xdeadbeef }, Local {}) + } + + #[task(shared = [&key])] + async fn foo(cx: foo::Context) { + let key: &u32 = cx.shared.key; + hprintln!("foo(key = {:#x})", key); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + + #[task(priority = 2, shared = [&key])] + async fn bar(cx: bar::Context) { + hprintln!("bar(key = {:#x})", cx.shared.key); + } +} diff --git a/examples/lm3s6965/examples/peripherals-taken.rs b/examples/lm3s6965/examples/peripherals-taken.rs new file mode 100644 index 0000000..2f63001 --- /dev/null +++ b/examples/lm3s6965/examples/peripherals-taken.rs @@ -0,0 +1,28 @@ +//! examples/peripherals-taken.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::debug; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + assert!(cortex_m::Peripherals::take().is_none()); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + + (Shared {}, Local {}) + } +} diff --git a/examples/lm3s6965/examples/pool.rs_old b/examples/lm3s6965/examples/pool.rs_old new file mode 100644 index 0000000..b399202 --- /dev/null +++ b/examples/lm3s6965/examples/pool.rs_old @@ -0,0 +1,69 @@ +//! examples/pool.rs + +#![no_main] +#![no_std] +#![deny(warnings)] + +use heapless::{ + pool, + pool::singleton::{Box, Pool}, +}; +use panic_semihosting as _; +use rtic::app; + +// Declare a pool of 128-byte memory blocks +pool!(P: [u8; 128]); + +#[app(device = lm3s6965, dispatchers = [SSI0, QEI0])] +mod app { + use crate::{Box, Pool}; + use cortex_m_semihosting::debug; + use lm3s6965::Interrupt; + + // Import the memory pool into scope + use super::P; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init(local = [memory: [u8; 512] = [0; 512]])] + fn init(cx: init::Context) -> (Shared, Local) { + // Increase the capacity of the memory pool by ~4 + P::grow(cx.local.memory); + + rtic::pend(Interrupt::I2C0); + + (Shared {}, Local {}) + } + + #[task(binds = I2C0, priority = 2)] + fn i2c0(_: i2c0::Context) { + // claim a memory block, initialize it and .. + let x = P::alloc().unwrap().init([0u8; 128]); + + // .. send it to the `foo` task + foo::spawn(x).ok().unwrap(); + + // send another block to the task `bar` + bar::spawn(P::alloc().unwrap().init([0u8; 128])) + .ok() + .unwrap(); + } + + #[task] + async fn foo(_: foo::Context, _x: Box

) { + // explicitly return the block to the pool + drop(_x); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + + #[task(priority = 2)] + async fn bar(_: bar::Context, _x: Box

) { + // this is done automatically so we can omit the call to `drop` + // drop(_x); + } +} diff --git a/examples/lm3s6965/examples/preempt.rs b/examples/lm3s6965/examples/preempt.rs new file mode 100644 index 0000000..62c67dc --- /dev/null +++ b/examples/lm3s6965/examples/preempt.rs @@ -0,0 +1,48 @@ +//! examples/preempt.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; +use rtic::app; + +#[app(device = lm3s6965, dispatchers = [SSI0, QEI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + + (Shared {}, Local {}) + } + + #[task(priority = 1)] + async fn foo(_: foo::Context) { + hprintln!("foo - start"); + baz::spawn().unwrap(); + hprintln!("foo - end"); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + + #[task(priority = 2)] + async fn bar(_: bar::Context) { + hprintln!(" bar"); + } + + #[task(priority = 2)] + async fn baz(_: baz::Context) { + hprintln!(" baz - start"); + bar::spawn().unwrap(); + hprintln!(" baz - end"); + } +} diff --git a/examples/lm3s6965/examples/prio-inversion.rs b/examples/lm3s6965/examples/prio-inversion.rs new file mode 100644 index 0000000..36dcbe2 --- /dev/null +++ b/examples/lm3s6965/examples/prio-inversion.rs @@ -0,0 +1,86 @@ +//! examples/prio-inversion.rs +//! +//! Here we test to make sure we don't have priority inversion. + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; +use rtic::app; + +// t1 p1 use b, a +// t2 p2 use a +// t3 p3 +// t4 p4 use b +// +// so t1 start , take b take a, pend t3 +// t3 should not start +// try to see if it starts, IT SHOULD NOT + +#[app(device = lm3s6965, dispatchers = [SSI0, QEI0, GPIOA, GPIOB])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared { + a: u32, + b: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + + (Shared { a: 0, b: 0 }, Local {}) + } + + #[task(priority = 1, shared = [a, b])] + async fn foo(cx: foo::Context) { + let foo::SharedResources { mut a, mut b, .. } = cx.shared; + + hprintln!("foo - start"); + + // basepri = 0 + b.lock(|b| { + // basepri = max(basepri = 0, ceil(b) = 4) = 4 + a.lock(|a| { + // basepri = max(basepri = 4, ceil(a) = 2) = 4 + + hprintln!("pre baz spawn {} {}", a, b); + + // This spawn should be blocked as prio(baz) = 3 + baz::spawn().unwrap(); + + hprintln!("post baz spawn {} {}", a, b); + }); + // basepri = 4 + }); + // basepri = 0 + + hprintln!("foo - end"); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + + #[task(priority = 2, shared = [a])] + async fn bar(_: bar::Context) { + hprintln!(" bar"); + } + + #[task(priority = 3)] + async fn baz(_: baz::Context) { + hprintln!(" baz - start"); + hprintln!(" baz - end"); + } + + #[task(priority = 4, shared = [b])] + async fn pow(_: pow::Context) { + hprintln!(" pow - start"); + hprintln!(" pow - end"); + } +} diff --git a/examples/lm3s6965/examples/ramfunc.rs b/examples/lm3s6965/examples/ramfunc.rs new file mode 100644 index 0000000..d072ecb --- /dev/null +++ b/examples/lm3s6965/examples/ramfunc.rs @@ -0,0 +1,49 @@ +//! examples/ramfunc.rs +//! TODO: verify that ram-sections are properly used + +#![no_main] +#![no_std] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app( + device = lm3s6965, + dispatchers = [ + UART0, + #[link_section = ".data.UART1"] + UART1 + ]) +] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + + (Shared {}, Local {}) + } + + #[inline(never)] + #[task] + async fn foo(_: foo::Context) { + hprintln!("foo"); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + + // run this task from RAM + #[inline(never)] + #[link_section = ".data.bar"] + #[task(priority = 2)] + async fn bar(_: bar::Context) { + foo::spawn().unwrap(); + } +} diff --git a/examples/lm3s6965/examples/resource-user-struct.rs b/examples/lm3s6965/examples/resource-user-struct.rs new file mode 100644 index 0000000..cad42d7 --- /dev/null +++ b/examples/lm3s6965/examples/resource-user-struct.rs @@ -0,0 +1,72 @@ +//! examples/resource.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use lm3s6965::Interrupt; + + #[shared] + struct Shared { + // A resource + shared: u32, + } + + // Should not collide with the struct above + #[allow(dead_code)] + struct Shared2 { + // A resource + shared: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + rtic::pend(Interrupt::UART0); + rtic::pend(Interrupt::UART1); + + (Shared { shared: 0 }, Local {}) + } + + // `shared` cannot be accessed from this context + #[idle] + fn idle(_cx: idle::Context) -> ! { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + + // error: no `shared` field in `idle::Context` + // _cx.shared.shared += 1; + + loop {} + } + + // `shared` can be accessed from this context + #[task(binds = UART0, shared = [shared])] + fn uart0(mut cx: uart0::Context) { + let shared = cx.shared.shared.lock(|shared| { + *shared += 1; + *shared + }); + + hprintln!("UART0: shared = {}", shared); + } + + // `shared` can be accessed from this context + #[task(binds = UART1, shared = [shared])] + fn uart1(mut cx: uart1::Context) { + let shared = cx.shared.shared.lock(|shared| { + *shared += 1; + *shared + }); + + hprintln!("UART1: shared = {}", shared); + } +} diff --git a/examples/lm3s6965/examples/shared.rs b/examples/lm3s6965/examples/shared.rs new file mode 100644 index 0000000..79ebab8 --- /dev/null +++ b/examples/lm3s6965/examples/shared.rs @@ -0,0 +1,51 @@ +//! examples/late.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use heapless::spsc::{Consumer, Producer, Queue}; + use lm3s6965::Interrupt; + + #[shared] + struct Shared { + p: Producer<'static, u32, 5>, + c: Consumer<'static, u32, 5>, + } + + #[local] + struct Local {} + + #[init(local = [q: Queue = Queue::new()])] + fn init(cx: init::Context) -> (Shared, Local) { + let (p, c) = cx.local.q.split(); + + // Initialization of shared resources + (Shared { p, c }, Local {}) + } + + #[idle(shared = [c])] + fn idle(mut c: idle::Context) -> ! { + loop { + if let Some(byte) = c.shared.c.lock(|c| c.dequeue()) { + hprintln!("received message: {}", byte); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } else { + rtic::pend(Interrupt::UART0); + } + } + } + + #[task(binds = UART0, shared = [p])] + fn uart0(mut c: uart0::Context) { + c.shared.p.lock(|p| p.enqueue(42).unwrap()); + } +} diff --git a/examples/lm3s6965/examples/smallest.rs b/examples/lm3s6965/examples/smallest.rs new file mode 100644 index 0000000..fee3f05 --- /dev/null +++ b/examples/lm3s6965/examples/smallest.rs @@ -0,0 +1,27 @@ +//! examples/smallest.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; // panic handler +use rtic::app; + +#[app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::debug; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + (Shared {}, Local {}) + } +} diff --git a/examples/lm3s6965/examples/spawn.rs b/examples/lm3s6965/examples/spawn.rs new file mode 100644 index 0000000..448bcda --- /dev/null +++ b/examples/lm3s6965/examples/spawn.rs @@ -0,0 +1,35 @@ +//! examples/spawn.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + hprintln!("init"); + foo::spawn().unwrap(); + + (Shared {}, Local {}) + } + + #[task] + async fn foo(_: foo::Context) { + hprintln!("foo"); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } +} diff --git a/examples/lm3s6965/examples/spawn_arguments.rs b/examples/lm3s6965/examples/spawn_arguments.rs new file mode 100644 index 0000000..61c4608 --- /dev/null +++ b/examples/lm3s6965/examples/spawn_arguments.rs @@ -0,0 +1,34 @@ +//! examples/spawn_arguments.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn(1, 1).unwrap(); + assert!(foo::spawn(1, 4).is_err()); // The capacity of `foo` is reached + + (Shared {}, Local {}) + } + + #[task] + async fn foo(_c: foo::Context, x: i32, y: u32) { + hprintln!("foo {}, {}", x, y); + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } +} diff --git a/examples/lm3s6965/examples/spawn_err.rs b/examples/lm3s6965/examples/spawn_err.rs new file mode 100644 index 0000000..e5a9420 --- /dev/null +++ b/examples/lm3s6965/examples/spawn_err.rs @@ -0,0 +1,39 @@ +//! examples/spawn_err.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + hprintln!("init"); + foo::spawn().unwrap(); + match foo::spawn() { + Ok(_) => {} + Err(()) => hprintln!("Cannot spawn a spawned (running) task!"), + } + + (Shared {}, Local {}) + } + + #[task] + async fn foo(_: foo::Context) { + hprintln!("foo"); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } +} diff --git a/examples/lm3s6965/examples/spawn_loop.rs b/examples/lm3s6965/examples/spawn_loop.rs new file mode 100644 index 0000000..13e386a --- /dev/null +++ b/examples/lm3s6965/examples/spawn_loop.rs @@ -0,0 +1,42 @@ +//! examples/spawn_loop.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + hprintln!("init"); + + (Shared {}, Local {}) + } + + #[idle] + fn idle(_: idle::Context) -> ! { + for _ in 0..3 { + foo::spawn().unwrap(); + hprintln!("idle"); + } + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + loop {} + } + + #[task(priority = 1)] + async fn foo(_: foo::Context) { + hprintln!("foo"); + } +} diff --git a/examples/lm3s6965/examples/static.rs b/examples/lm3s6965/examples/static.rs new file mode 100644 index 0000000..fec73fc --- /dev/null +++ b/examples/lm3s6965/examples/static.rs @@ -0,0 +1,60 @@ +//! examples/static.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [UART0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + use heapless::spsc::{Consumer, Producer, Queue}; + + #[shared] + struct Shared {} + + #[local] + struct Local { + p: Producer<'static, u32, 5>, + c: Consumer<'static, u32, 5>, + } + + #[init(local = [q: Queue = Queue::new()])] + fn init(cx: init::Context) -> (Shared, Local) { + // q has 'static life-time so after the split and return of `init` + // it will continue to exist and be allocated + let (p, c) = cx.local.q.split(); + + foo::spawn().unwrap(); + + (Shared {}, Local { p, c }) + } + + #[idle(local = [c])] + fn idle(c: idle::Context) -> ! { + loop { + // Lock-free access to the same underlying queue! + if let Some(data) = c.local.c.dequeue() { + hprintln!("received message: {}", data); + + // Run foo until data + if data == 3 { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } else { + foo::spawn().unwrap(); + } + } + } + } + + #[task(local = [p, state: u32 = 0], priority = 1)] + async fn foo(c: foo::Context) { + *c.local.state += 1; + + // Lock-free access to the same underlying queue! + c.local.p.enqueue(*c.local.state).unwrap(); + } +} diff --git a/examples/lm3s6965/examples/t-binds.rs b/examples/lm3s6965/examples/t-binds.rs new file mode 100644 index 0000000..01c262c --- /dev/null +++ b/examples/lm3s6965/examples/t-binds.rs @@ -0,0 +1,45 @@ +//! [compile-pass] Check that `binds` works as advertised + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::debug; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + + (Shared {}, Local {}) + } + + // Cortex-M exception + #[task(binds = SVCall)] + fn foo(c: foo::Context) { + crate::foo_trampoline(c) + } + + // LM3S6965 interrupt + #[task(binds = UART0)] + fn bar(c: bar::Context) { + crate::bar_trampoline(c) + } +} + +#[allow(dead_code)] +fn foo_trampoline(_: app::foo::Context) {} + +#[allow(dead_code)] +fn bar_trampoline(_: app::bar::Context) {} diff --git a/examples/lm3s6965/examples/t-cfg-resources.rs b/examples/lm3s6965/examples/t-cfg-resources.rs new file mode 100644 index 0000000..2ddfae7 --- /dev/null +++ b/examples/lm3s6965/examples/t-cfg-resources.rs @@ -0,0 +1,44 @@ +//! [compile-pass] check that `#[cfg]` attributes applied on resources work + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::debug; + + #[shared] + struct Shared { + // A conditionally compiled resource behind feature_x + #[cfg(feature = "feature_x")] + x: u32, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + + ( + Shared { + #[cfg(feature = "feature_x")] + x: 0, + }, + Local {}, + ) + } + + #[idle] + fn idle(_cx: idle::Context) -> ! { + loop { + cortex_m::asm::nop(); + } + } +} diff --git a/examples/lm3s6965/examples/t-htask-main.rs b/examples/lm3s6965/examples/t-htask-main.rs new file mode 100644 index 0000000..61280f8 --- /dev/null +++ b/examples/lm3s6965/examples/t-htask-main.rs @@ -0,0 +1,32 @@ +//! examples/t-task-main.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::debug; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + rtic::pend(lm3s6965::Interrupt::UART0); + + (Shared {}, Local {}) + } + + #[task(binds = UART0)] + fn taskmain(_: taskmain::Context) { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } +} diff --git a/examples/lm3s6965/examples/t-idle-main.rs b/examples/lm3s6965/examples/t-idle-main.rs new file mode 100644 index 0000000..88566a9 --- /dev/null +++ b/examples/lm3s6965/examples/t-idle-main.rs @@ -0,0 +1,33 @@ +//! examples/t-idle-main.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965)] +mod app { + use cortex_m_semihosting::debug; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + (Shared {}, Local {}) + } + + #[idle] + fn taskmain(_: taskmain::Context) -> ! { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + loop { + cortex_m::asm::nop(); + } + } +} diff --git a/examples/lm3s6965/examples/t-late-not-send.rs b/examples/lm3s6965/examples/t-late-not-send.rs new file mode 100644 index 0000000..be5cc66 --- /dev/null +++ b/examples/lm3s6965/examples/t-late-not-send.rs @@ -0,0 +1,50 @@ +//! [compile-pass] shared resources don't need to be `Send` if they are owned by `idle` + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use core::marker::PhantomData; +use panic_semihosting as _; + +/// Not send +pub struct NotSend { + _0: PhantomData<*const ()>, +} + +#[rtic::app(device = lm3s6965)] +mod app { + use super::NotSend; + use core::marker::PhantomData; + use cortex_m_semihosting::debug; + + #[shared] + struct Shared { + x: NotSend, + y: Option, + } + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + ( + Shared { + x: NotSend { _0: PhantomData }, + y: None, + }, + Local {}, + ) + } + + #[idle(shared = [x, y])] + fn idle(_: idle::Context) -> ! { + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + loop { + cortex_m::asm::nop(); + } + } +} diff --git a/examples/lm3s6965/examples/task.rs b/examples/lm3s6965/examples/task.rs new file mode 100644 index 0000000..b6b6bbd --- /dev/null +++ b/examples/lm3s6965/examples/task.rs @@ -0,0 +1,57 @@ +//! examples/task.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use panic_semihosting as _; + +#[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])] +mod app { + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared {} + + #[local] + struct Local {} + + #[init] + fn init(_: init::Context) -> (Shared, Local) { + foo::spawn().unwrap(); + + (Shared {}, Local {}) + } + + #[task] + async fn foo(_: foo::Context) { + hprintln!("foo - start"); + + // spawns `bar` onto the task scheduler + // `foo` and `bar` have the same priority so `bar` will not run until + // after `foo` terminates + bar::spawn().unwrap(); + + hprintln!("foo - middle"); + + // spawns `baz` onto the task scheduler + // `baz` has higher priority than `foo` so it immediately preempts `foo` + baz::spawn().unwrap(); + + hprintln!("foo - end"); + } + + #[task] + async fn bar(_: bar::Context) { + hprintln!("bar"); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } + + #[task(priority = 2)] + async fn baz(_: baz::Context) { + hprintln!("baz"); + } +} diff --git a/examples/lm3s6965/examples/zero-prio-task.rs b/examples/lm3s6965/examples/zero-prio-task.rs new file mode 100644 index 0000000..8cfd705 --- /dev/null +++ b/examples/lm3s6965/examples/zero-prio-task.rs @@ -0,0 +1,61 @@ +//! examples/zero-prio-task.rs + +#![no_main] +#![no_std] +#![deny(warnings)] +#![deny(unsafe_code)] +#![deny(missing_docs)] + +use core::marker::PhantomData; +use panic_semihosting as _; + +/// Does not impl send +pub struct NotSend { + _0: PhantomData<*const ()>, +} + +#[rtic::app(device = lm3s6965, peripherals = true)] +mod app { + use super::NotSend; + use core::marker::PhantomData; + use cortex_m_semihosting::{debug, hprintln}; + + #[shared] + struct Shared { + x: NotSend, + } + + #[local] + struct Local { + y: NotSend, + } + + #[init] + fn init(_cx: init::Context) -> (Shared, Local) { + hprintln!("init"); + + async_task::spawn().unwrap(); + async_task2::spawn().unwrap(); + + ( + Shared { + x: NotSend { _0: PhantomData }, + }, + Local { + y: NotSend { _0: PhantomData }, + }, + ) + } + + #[task(priority = 0, shared = [x], local = [y])] + async fn async_task(_: async_task::Context) { + hprintln!("hello from async"); + } + + #[task(priority = 0, shared = [x])] + async fn async_task2(_: async_task2::Context) { + hprintln!("hello from async2"); + + debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator + } +} diff --git a/rtic-macros/CHANGELOG.md b/rtic-macros/CHANGELOG.md index 66bd9bc..a0d761b 100644 --- a/rtic-macros/CHANGELOG.md +++ b/rtic-macros/CHANGELOG.md @@ -11,6 +11,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top! ### Added +- Unstable support for RISC-V targets compatible with `riscv-slic` - RTIC v2 now works on stable. - Unstable ESP32-C3 support. diff --git a/rtic-macros/Cargo.toml b/rtic-macros/Cargo.toml index 423fe31..443ed0d 100644 --- a/rtic-macros/Cargo.toml +++ b/rtic-macros/Cargo.toml @@ -36,8 +36,8 @@ cortex-m-basepri = [] riscv-esp32c3 = [] # riscv-clic = [] # riscv-ch32 = [] - - +riscv-slic = [] + # backend API test test-template = [] diff --git a/rtic-macros/src/codegen.rs b/rtic-macros/src/codegen.rs index c04f213..060db6d 100644 --- a/rtic-macros/src/codegen.rs +++ b/rtic-macros/src/codegen.rs @@ -8,6 +8,7 @@ pub mod bindings; mod assertions; mod async_dispatchers; +mod extra_mods; mod hardware_tasks; mod idle; mod init; diff --git a/rtic-macros/src/codegen/async_dispatchers.rs b/rtic-macros/src/codegen/async_dispatchers.rs index 9144b2a..3d166ca 100644 --- a/rtic-macros/src/codegen/async_dispatchers.rs +++ b/rtic-macros/src/codegen/async_dispatchers.rs @@ -2,7 +2,7 @@ use crate::syntax::ast::App; use crate::{ analyze::Analysis, codegen::{ - bindings::{async_entry, handler_config, interrupt_entry, interrupt_exit}, + bindings::{async_entry, handler_config, interrupt_entry, interrupt_exit, interrupt_mod}, util, }, }; @@ -36,10 +36,9 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 { }; let pend_interrupt = if level > 0 { - let device = &app.args.device; - let enum_ = util::interrupt_ident(); + let int_mod = interrupt_mod(app); - quote!(rtic::export::pend(#device::#enum_::#dispatcher_name);) + quote!(rtic::export::pend(#int_mod::#dispatcher_name);) } else { // For 0 priority tasks we don't need to pend anything quote!() diff --git a/rtic-macros/src/codegen/bindings.rs b/rtic-macros/src/codegen/bindings.rs index 60605f3..501ccdf 100644 --- a/rtic-macros/src/codegen/bindings.rs +++ b/rtic-macros/src/codegen/bindings.rs @@ -2,7 +2,8 @@ feature = "cortex-m-source-masking", feature = "cortex-m-basepri", feature = "test-template", - feature = "riscv-esp32c3" + feature = "riscv-esp32c3", + feature = "riscv-slic", )))] compile_error!("No backend selected"); @@ -22,4 +23,10 @@ mod template; pub use esp32c3::*; #[cfg(feature = "riscv-esp32c3")] -mod esp32c3; \ No newline at end of file +mod esp32c3; + +#[cfg(feature = "riscv-slic")] +pub use riscv_slic::*; + +#[cfg(feature = "riscv-slic")] +mod riscv_slic; diff --git a/rtic-macros/src/codegen/bindings/cortex.rs b/rtic-macros/src/codegen/bindings/cortex.rs index 69b5ee5..5c56261 100644 --- a/rtic-macros/src/codegen/bindings/cortex.rs +++ b/rtic-macros/src/codegen/bindings/cortex.rs @@ -35,6 +35,12 @@ pub fn interrupt_ident() -> Ident { Ident::new("interrupt", span) } +pub fn interrupt_mod(app: &App) -> TokenStream2 { + let device = &app.args.device; + let interrupt = interrupt_ident(); + quote!(#device::#interrupt) +} + pub fn check_stack_overflow_before_init( _app: &App, _analysis: &CodegenAnalysis, @@ -199,12 +205,16 @@ mod basepri { } } +pub fn pre_init_preprocessing(_app: &mut App, _analysis: &SyntaxAnalysis) -> parse::Result<()> { + Ok(()) +} + pub fn pre_init_checks(app: &App, _: &SyntaxAnalysis) -> Vec { let mut stmts = vec![]; // check that all dispatchers exists in the `Interrupt` enumeration regardless of whether // they are used or not - let interrupt = util::interrupt_ident(); + let interrupt = interrupt_ident(); let rt_err = util::rt_err_ident(); for name in app.args.dispatchers.keys() { @@ -217,7 +227,7 @@ pub fn pre_init_checks(app: &App, _: &SyntaxAnalysis) -> Vec { pub fn pre_init_enable_interrupts(app: &App, analysis: &CodegenAnalysis) -> Vec { let mut stmts = vec![]; - let interrupt = util::interrupt_ident(); + let interrupt = interrupt_ident(); let rt_err = util::rt_err_ident(); let device = &app.args.device; let nvic_prio_bits = quote!(#device::NVIC_PRIO_BITS); @@ -381,3 +391,7 @@ pub fn handler_config( ) -> Vec { vec![] } + +pub fn extra_modules(_app: &App, _analysis: &SyntaxAnalysis) -> Vec { + vec![] +} diff --git a/rtic-macros/src/codegen/bindings/esp32c3.rs b/rtic-macros/src/codegen/bindings/esp32c3.rs index 4b14cae..f8ea22a 100644 --- a/rtic-macros/src/codegen/bindings/esp32c3.rs +++ b/rtic-macros/src/codegen/bindings/esp32c3.rs @@ -55,10 +55,20 @@ mod esp32c3 { Ident::new("Interrupt", span) } + pub fn interrupt_mod(app: &App) -> TokenStream2 { + let device = &app.args.device; + let interrupt = interrupt_ident(); + quote!(#device::#interrupt) + } + pub fn extra_assertions(_: &App, _: &SyntaxAnalysis) -> Vec { vec![] } + pub fn pre_init_preprocessing(_app: &mut App, _analysis: &SyntaxAnalysis) -> parse::Result<()> { + Ok(()) + } + pub fn pre_init_checks(app: &App, _: &SyntaxAnalysis) -> Vec { let mut stmts = vec![]; // check that all dispatchers exists in the `Interrupt` enumeration regardless of whether @@ -232,3 +242,7 @@ mod esp32c3 { stmts } } + +pub fn extra_modules(_app: &App, _analysis: &SyntaxAnalysis) -> Vec { + vec![] +} diff --git a/rtic-macros/src/codegen/bindings/riscv_slic.rs b/rtic-macros/src/codegen/bindings/riscv_slic.rs new file mode 100644 index 0000000..c9bf50a --- /dev/null +++ b/rtic-macros/src/codegen/bindings/riscv_slic.rs @@ -0,0 +1,255 @@ +use crate::{ + analyze::Analysis as CodegenAnalysis, + syntax::{ + analyze::Analysis as SyntaxAnalysis, + ast::{App, Dispatcher}, + }, +}; +use proc_macro2::{Span, TokenStream as TokenStream2}; +use quote::quote; +use std::{collections::HashSet, vec}; +use syn::{parse, Attribute, Ident}; + +/// Utility function to get the SLIC interrupt module. +pub fn interrupt_ident() -> Ident { + let span = Span::call_site(); + Ident::new("Interrupt", span) +} + +pub fn interrupt_mod(_app: &App) -> TokenStream2 { + let interrupt = interrupt_ident(); + quote!(slic::#interrupt) +} + +/// This macro implements the [`rtic::Mutex`] trait for shared resources using the SLIC. +#[allow(clippy::too_many_arguments)] +pub fn impl_mutex( + _app: &App, + _analysis: &CodegenAnalysis, + cfgs: &[Attribute], + resources_prefix: bool, + name: &Ident, + ty: &TokenStream2, + ceiling: u8, + ptr: &TokenStream2, +) -> TokenStream2 { + let path = if resources_prefix { + quote!(shared_resources::#name) + } else { + quote!(#name) + }; + + quote!( + #(#cfgs)* + impl<'a> rtic::Mutex for #path<'a> { + type T = #ty; + + #[inline(always)] + fn lock(&mut self, f: impl FnOnce(&mut #ty) -> RTIC_INTERNAL_R) -> RTIC_INTERNAL_R { + + const CEILING: u8 = #ceiling; + + unsafe { + rtic::export::lock(#ptr, CEILING, f) + } + } + } + ) +} + +/// This macro is used to define additional compile-time assertions in case the platform needs it. +/// The Cortex-M implementations do not use it. Thus, we think we do not need it either. +pub fn extra_assertions(_app: &App, _analysis: &SyntaxAnalysis) -> Vec { + vec![] +} + +pub fn pre_init_preprocessing(app: &mut App, _analysis: &SyntaxAnalysis) -> parse::Result<()> { + app.args.core = false; // RISC-V SLIC is not compatible with using core peripherals + if !app.args.dispatchers.is_empty() { + return Err(parse::Error::new( + Span::call_site(), + "this backend does not support explicit interrupt dispatchers; remove the `dispatchers` argument from `#[app]`", + )); + } + + // Compute the number of handlers we need to dispatch the software tasks + let soft_priorities = app + .software_tasks + .iter() + .map(|(_, task)| task.args.priority) + .filter(|prio| *prio > 0) + .collect::>(); + + for i in 0..soft_priorities.len() { + let dispatcher_ident = Ident::new(&format!("__RTICDispatcher{}", i), Span::call_site()); + app.args + .dispatchers + .insert(dispatcher_ident, Dispatcher { attrs: vec![] }); + } + + Ok(()) +} + +/// This macro is used to check at run-time that all the interruption dispatchers exist. +pub fn pre_init_checks(app: &App, _analysis: &SyntaxAnalysis) -> Vec { + let mut stmts: Vec = vec![]; + let int_mod = interrupt_mod(app); + + // check that all dispatchers exists in the `slic::Interrupt` enumeration + for name in app.args.dispatchers.keys() { + stmts.push(quote!(let _ = #int_mod::#name;)); + } + + stmts +} + +/// This macro must perform all the required operations to activate the +/// interrupt sources with their corresponding priority level. +pub fn pre_init_enable_interrupts(app: &App, analysis: &CodegenAnalysis) -> Vec { + let mut stmts = vec![]; + + // First, we reset and disable all the interrupt controllers + stmts.push(quote!(rtic::export::clear_interrupts();)); + + // Then, we set the corresponding priorities + let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id)); + for (&p, name) in interrupt_ids.chain( + app.hardware_tasks + .values() + .map(|task| (&task.args.priority, &task.args.binds)), + ) { + stmts.push(quote!( + rtic::export::set_priority(slic::Interrupt::#name, #p); + )); + } + // Finally, we activate the interrupts + stmts.push(quote!(rtic::export::set_interrupts();)); + stmts +} + +/// Any additional checks that depend on the system architecture. +pub fn architecture_specific_analysis(app: &App, _analysis: &SyntaxAnalysis) -> parse::Result<()> { + // Check that there are enough external interrupts to dispatch the software tasks and the timer queue handler + let mut first = None; + let priorities = app + .software_tasks + .iter() + .map(|(name, task)| { + first = Some(name); + task.args.priority + }) + .filter(|prio| *prio > 0) + .collect::>(); + + let need = priorities.len(); + let given = app.args.dispatchers.len(); + if need > given { + let s = { + format!( + "not enough interrupts to dispatch \ + all software tasks (need: {need}; given: {given})" + ) + }; + + return Err(parse::Error::new(first.unwrap().span(), s)); + } + + if app.args.backend.is_none() { + return Err(parse::Error::new( + Span::call_site(), + "SLIC requires backend-specific configuration", + )); + } + + Ok(()) +} + +/// Macro to add statements to be executed at the beginning of all the interrupt handlers. +pub fn interrupt_entry(_app: &App, _analysis: &CodegenAnalysis) -> Vec { + vec![] +} + +/// Macro to add statements to be executed at the end of all the interrupt handlers. +pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec { + vec![] +} + +pub fn check_stack_overflow_before_init( + _app: &App, + _analysis: &CodegenAnalysis, +) -> Vec { + vec![quote!( + // Check for stack overflow using symbols from `risc-v-rt`. + extern "C" { + pub static _stack_start: u32; + pub static _ebss: u32; + } + + let stack_start = &_stack_start as *const _ as u32; + let ebss = &_ebss as *const _ as u32; + + if stack_start > ebss { + // No flip-link usage, check the SP for overflow. + if rtic::export::read_sp() <= ebss { + panic!("Stack overflow after allocating executors"); + } + } + )] +} + +pub fn async_entry( + _app: &App, + _analysis: &CodegenAnalysis, + _dispatcher_name: Ident, +) -> Vec { + vec![] +} + +/// Macro to define a maximum priority level for async tasks. +pub fn async_prio_limit(_app: &App, analysis: &CodegenAnalysis) -> Vec { + let max = if let Some(max) = analysis.max_async_prio { + quote!(#max) + } else { + quote!(u8::MAX) // No limit + }; + + vec![quote!( + /// Holds the maximum priority level for use by async HAL drivers. + #[no_mangle] + static RTIC_ASYNC_MAX_LOGICAL_PRIO: u8 = #max; + )] +} + +pub fn handler_config( + _app: &App, + _analysis: &CodegenAnalysis, + _dispatcher_name: Ident, +) -> Vec { + vec![] +} + +/// The SLIC requires us to call to the [`riscv_rtic::codegen`] macro to generate +/// the appropriate SLIC structure, interrupt enumerations, etc. +pub fn extra_modules(app: &App, _analysis: &SyntaxAnalysis) -> Vec { + let mut stmts = vec![]; + + let hw_slice: Vec<_> = app + .hardware_tasks + .values() + .map(|task| &task.args.binds) + .collect(); + let sw_slice: Vec<_> = app.args.dispatchers.keys().collect(); + + let swi_slice: Vec<_> = hw_slice.iter().chain(sw_slice.iter()).collect(); + + let device = &app.args.device; + + stmts.push(quote!( + use rtic::export::riscv_slic; + )); + let hart_id = &app.args.backend.as_ref().unwrap().hart_id; + + stmts.push(quote!(rtic::export::codegen!(pac = #device, swi = [#(#swi_slice,)*], backend = [hart_id = #hart_id]);)); + + stmts +} diff --git a/rtic-macros/src/codegen/bindings/template.rs b/rtic-macros/src/codegen/bindings/template.rs index b5488b7..ecb46d5 100644 --- a/rtic-macros/src/codegen/bindings/template.rs +++ b/rtic-macros/src/codegen/bindings/template.rs @@ -6,40 +6,55 @@ use proc_macro2::TokenStream as TokenStream2; use quote::quote; use syn::{parse, Attribute, Ident}; +pub fn interrupt_ident() -> Ident { + let span = Span::call_site(); + Ident::new("interrupt", span) +} + +pub fn interrupt_mod(app: &App) -> TokenStream2 { + let device = &app.args.device; + let interrupt = interrupt_ident(); + quote!(#device::#interrupt) +} + pub fn impl_mutex( - _app: &App, - _analysis: &CodegenAnalysis, - _cfgs: &[Attribute], - _resources_prefix: bool, - _name: &Ident, - _ty: &TokenStream2, - _ceiling: u8, - _ptr: &TokenStream2, + app: &App, + analysis: &CodegenAnalysis, + cfgs: &[Attribute], + resources_prefix: bool, + name: &Ident, + ty: &TokenStream2, + ceiling: u8, + ptr: &TokenStream2, ) -> TokenStream2 { quote!() } -pub fn extra_assertions(_app: &App, _analysis: &SyntaxAnalysis) -> Vec { +pub fn extra_assertions(app: &App, analysis: &SyntaxAnalysis) -> Vec { vec![] } -pub fn pre_init_checks(_app: &App, _analysis: &SyntaxAnalysis) -> Vec { +pub fn pre_init_preprocessing(app: &mut App, analysis: &SyntaxAnalysis) -> parse::Result<()> { + Ok(()) +} + +pub fn pre_init_checks(app: &App, analysis: &SyntaxAnalysis) -> Vec { vec![] } -pub fn pre_init_enable_interrupts(_app: &App, _analysis: &CodegenAnalysis) -> Vec { +pub fn pre_init_enable_interrupts(app: &App, analysis: &CodegenAnalysis) -> Vec { vec![] } -pub fn architecture_specific_analysis(_app: &App, _analysis: &SyntaxAnalysis) -> parse::Result<()> { +pub fn architecture_specific_analysis(app: &App, analysis: &SyntaxAnalysis) -> parse::Result<()> { Ok(()) } -pub fn interrupt_entry(_app: &App, _analysis: &CodegenAnalysis) -> Vec { +pub fn interrupt_entry(app: &App, analysis: &CodegenAnalysis) -> Vec { vec![] } -pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec { +pub fn interrupt_exit(app: &App, analysis: &CodegenAnalysis) -> Vec { vec![] } @@ -51,20 +66,25 @@ pub fn check_stack_overflow_before_init( } pub fn async_entry( - _app: &App, - _analysis: &CodegenAnalysis, - _dispatcher_name: Ident, + app: &App, + analysis: &CodegenAnalysis, + dispatcher_name: Ident, ) -> Vec { vec![] } -pub fn async_prio_limit(app: &App, _analysis: &CodegenAnalysis) -> Vec { +pub fn async_prio_limit(app: &App, analysis: &CodegenAnalysis) -> Vec { vec![] } + pub fn handler_config( - _app: &App, - _analysis: &CodegenAnalysis, + app: &App, + analysis: &CodegenAnalysis, dispatcher_name: Ident, ) -> Vec { vec![] } + +pub fn extra_modules(app: &App, analysis: &SyntaxAnalysis) -> Vec { + vec![] +} diff --git a/rtic-macros/src/codegen/extra_mods.rs b/rtic-macros/src/codegen/extra_mods.rs new file mode 100644 index 0000000..b92dda6 --- /dev/null +++ b/rtic-macros/src/codegen/extra_mods.rs @@ -0,0 +1,9 @@ +use super::bindings::extra_modules; +use crate::analyze::Analysis; +use crate::syntax::ast::App; +use proc_macro2::TokenStream as TokenStream2; + +/// Generates code that runs before `#[init]` +pub fn codegen(app: &App, analysis: &Analysis) -> Vec { + extra_modules(app, analysis) +} diff --git a/rtic-macros/src/codegen/main.rs b/rtic-macros/src/codegen/main.rs index 5612796..80f2cf6 100644 --- a/rtic-macros/src/codegen/main.rs +++ b/rtic-macros/src/codegen/main.rs @@ -1,4 +1,3 @@ -use super::{assertions, post_init, pre_init}; use crate::{ analyze::Analysis, codegen::{bindings, util}, @@ -7,8 +6,12 @@ use crate::{ use proc_macro2::TokenStream as TokenStream2; use quote::quote; +use super::{assertions, extra_mods, post_init, pre_init}; + /// Generates code for `fn main` pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 { + let extra_mods_stmts = extra_mods::codegen(app, analysis); + let assertion_stmts = assertions::codegen(app, analysis); let pre_init_stmts = pre_init::codegen(app, analysis); @@ -40,9 +43,18 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 { let main = util::suffixed("main"); let init_name = &app.init.name; + + let init_args = if app.args.core { + quote!(core.into(), executors_size) + } else { + quote!(executors_size) + }; + let msp_check = bindings::check_stack_overflow_before_init(app, analysis); quote!( + #(#extra_mods_stmts)* + #[doc(hidden)] #[no_mangle] unsafe extern "C" fn #main() -> ! { @@ -63,7 +75,7 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 { // Wrap late_init_stmts in a function to ensure that stack space is reclaimed. __rtic_init_resources(||{ - let (shared_resources, local_resources) = #init_name(#init_name::Context::new(core.into(), executors_size)); + let (shared_resources, local_resources) = #init_name(#init_name::Context::new(#init_args)); #(#post_init_stmts)* }); diff --git a/rtic-macros/src/codegen/module.rs b/rtic-macros/src/codegen/module.rs index c8afe07..17c8ce7 100644 --- a/rtic-macros/src/codegen/module.rs +++ b/rtic-macros/src/codegen/module.rs @@ -1,5 +1,5 @@ use crate::syntax::{ast::App, Context}; -use crate::{analyze::Analysis, codegen::util}; +use crate::{analyze::Analysis, codegen::bindings::interrupt_mod, codegen::util}; use proc_macro2::TokenStream as TokenStream2; use quote::quote; @@ -16,16 +16,20 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 { match ctxt { Context::Init => { - fields.push(quote!( - /// Core peripherals - pub core: rtic::export::Peripherals - )); - fields.push(quote!( /// The space used to allocate async executors in bytes. pub executors_size: usize )); + if app.args.core { + fields.push(quote!( + /// Core peripherals + pub core: rtic::export::Peripherals + )); + + values.push(quote!(core: core)); + } + if app.args.peripherals { let device = &app.args.device; @@ -43,8 +47,6 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 { )); values.push(quote!(cs: rtic::export::CriticalSection::new())); - - values.push(quote!(core)); values.push(quote!(executors_size)); } @@ -98,7 +100,11 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 { }; let core = if ctxt.is_init() { - Some(quote!(core: rtic::export::Peripherals, executors_size: usize)) + if app.args.core { + Some(quote!(core: rtic::export::Peripherals, executors_size: usize)) + } else { + Some(quote!(executors_size: usize)) + } } else { None }; @@ -144,10 +150,9 @@ pub fn codegen(ctxt: Context, app: &App, analysis: &Analysis) -> TokenStream2 { task_cfgs = cfgs.clone(); let pend_interrupt = if priority > 0 { - let device = &app.args.device; - let enum_ = util::interrupt_ident(); + let int_mod = interrupt_mod(app); let interrupt = &analysis.interrupts.get(&priority).expect("UREACHABLE").0; - quote!(rtic::export::pend(#device::#enum_::#interrupt);) + quote!(rtic::export::pend(#int_mod::#interrupt);) } else { quote!() }; diff --git a/rtic-macros/src/codegen/pre_init.rs b/rtic-macros/src/codegen/pre_init.rs index a2d0e8c..8de75ff 100644 --- a/rtic-macros/src/codegen/pre_init.rs +++ b/rtic-macros/src/codegen/pre_init.rs @@ -11,10 +11,12 @@ pub fn codegen(app: &App, analysis: &Analysis) -> Vec { // Disable interrupts -- `init` must run with interrupts disabled stmts.push(quote!(rtic::export::interrupt::disable();)); - 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(); - )); + if app.args.core { + 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(); + )); + } stmts.append(&mut pre_init_checks(app, analysis)); diff --git a/rtic-macros/src/codegen/util.rs b/rtic-macros/src/codegen/util.rs index b4682ee..dda7e29 100644 --- a/rtic-macros/src/codegen/util.rs +++ b/rtic-macros/src/codegen/util.rs @@ -3,8 +3,6 @@ use core::sync::atomic::{AtomicUsize, Ordering}; use proc_macro2::{Span, TokenStream as TokenStream2}; use quote::quote; use syn::{Ident, PatType}; -//hook the target specific interrupt_ident function -pub use super::bindings::interrupt_ident; const RTIC_INTERNAL: &str = "__rtic_internal"; diff --git a/rtic-macros/src/lib.rs b/rtic-macros/src/lib.rs index 38eed8f..c464ab0 100644 --- a/rtic-macros/src/lib.rs +++ b/rtic-macros/src/lib.rs @@ -14,13 +14,14 @@ macro_rules! with_backend { feature = "cortex-m-source-masking", feature = "cortex-m-basepri", feature = "test-template", - feature = "riscv-esp32c3" + feature = "riscv-esp32c3", + feature = "riscv-slic", ))] $($tokens)* }; } -with_backend! { mod: [analyze, check, codegen, syntax] } +with_backend! { mod: [analyze, check, codegen, preprocess, syntax] } with_backend! { use std::{fs, env, path::Path}; } with_backend! { use proc_macro::TokenStream; } @@ -47,11 +48,18 @@ with_backend! { /// Should never panic, cargo feeds a path which is later converted to a string #[proc_macro_attribute] pub fn app(_args: TokenStream, _input: TokenStream) -> TokenStream { - let (app, analysis) = match syntax::parse(_args, _input) { + let (mut app, analysis) = match syntax::parse(_args, _input) { Err(e) => return e.to_compile_error().into(), Ok(x) => x, }; + // Modify app based on backend before continuing + if let Err(e) = preprocess::app(&mut app, &analysis) { + return e.to_compile_error().into(); + } + let app = app; + // App is not mutable after this point + if let Err(e) = check::app(&app, &analysis) { return e.to_compile_error().into(); } @@ -109,6 +117,7 @@ with_backend! { feature = "cortex-m-source-masking", feature = "cortex-m-basepri", feature = "test-template", - feature = "riscv-esp32c3" + feature = "riscv-esp32c3", + feature = "riscv-slic", )))] compile_error!("Cannot compile. No backend feature selected."); diff --git a/rtic-macros/src/preprocess.rs b/rtic-macros/src/preprocess.rs new file mode 100644 index 0000000..2fcd10b --- /dev/null +++ b/rtic-macros/src/preprocess.rs @@ -0,0 +1,7 @@ +use crate::codegen::bindings::pre_init_preprocessing; +use crate::syntax::{analyze::Analysis, ast::App}; +use syn::parse; + +pub fn app(app: &mut App, analysis: &Analysis) -> parse::Result<()> { + pre_init_preprocessing(app, analysis) +} diff --git a/rtic-macros/src/syntax.rs b/rtic-macros/src/syntax.rs index d6f5a47..a44b1ec 100644 --- a/rtic-macros/src/syntax.rs +++ b/rtic-macros/src/syntax.rs @@ -12,6 +12,7 @@ use crate::syntax::ast::App; mod accessors; pub mod analyze; pub mod ast; +mod backend; mod check; mod parse; diff --git a/rtic-macros/src/syntax/ast.rs b/rtic-macros/src/syntax/ast.rs index f0067b8..06feb1f 100644 --- a/rtic-macros/src/syntax/ast.rs +++ b/rtic-macros/src/syntax/ast.rs @@ -2,7 +2,7 @@ use syn::{Attribute, Expr, Ident, Item, ItemUse, Pat, PatType, Path, Stmt, Type}; -use crate::syntax::Map; +use crate::syntax::{backend::BackendArgs, Map}; /// The `#[app]` attribute #[derive(Debug)] @@ -60,11 +60,17 @@ pub struct AppArgs { /// Device pub device: Path, - /// Peripherals + /// Core peripherals + pub core: bool, + + /// Device peripherals pub peripherals: bool, /// Interrupts used to dispatch software tasks pub dispatchers: Dispatchers, + + /// Backend-specific arguments + pub backend: Option, } /// The `init`-ialization function diff --git a/rtic-macros/src/syntax/backend.rs b/rtic-macros/src/syntax/backend.rs new file mode 100644 index 0000000..460ef56 --- /dev/null +++ b/rtic-macros/src/syntax/backend.rs @@ -0,0 +1,32 @@ +#[cfg(not(any( + feature = "cortex-m-source-masking", + feature = "cortex-m-basepri", + feature = "test-template", + feature = "riscv-esp32c3", + feature = "riscv-slic", +)))] +compile_error!("No backend selected"); + +#[cfg(any(feature = "cortex-m-source-masking", feature = "cortex-m-basepri"))] +pub use cortex::*; + +#[cfg(feature = "test-template")] +pub use template::*; + +#[cfg(feature = "riscv-esp32c3")] +pub use esp32c3::*; + +#[cfg(feature = "riscv-slic")] +pub use riscv_slic::*; + +#[cfg(any(feature = "cortex-m-source-masking", feature = "cortex-m-basepri"))] +mod cortex; + +#[cfg(feature = "test-template")] +mod template; + +#[cfg(feature = "riscv-esp32c3")] +mod esp32c3; + +#[cfg(feature = "riscv-slic")] +mod riscv_slic; diff --git a/rtic-macros/src/syntax/backend/cortex.rs b/rtic-macros/src/syntax/backend/cortex.rs new file mode 100644 index 0000000..b53e927 --- /dev/null +++ b/rtic-macros/src/syntax/backend/cortex.rs @@ -0,0 +1,16 @@ +use syn::{ + parse::{Parse, ParseStream}, + Error, Result, +}; + +#[derive(Debug)] +pub struct BackendArgs(); + +impl Parse for BackendArgs { + fn parse(input: ParseStream) -> Result { + Err(Error::new( + input.span(), + "cortex backend does not accept any arguments", + )) + } +} diff --git a/rtic-macros/src/syntax/backend/esp32c3.rs b/rtic-macros/src/syntax/backend/esp32c3.rs new file mode 100644 index 0000000..33143f4 --- /dev/null +++ b/rtic-macros/src/syntax/backend/esp32c3.rs @@ -0,0 +1,16 @@ +use syn::{ + parse::{Parse, ParseStream}, + Error, Result, +}; + +#[derive(Debug)] +pub struct BackendArgs(); + +impl Parse for BackendArgs { + fn parse(input: ParseStream) -> Result { + Err(Error::new( + input.span(), + "esp32c3 backend does not accept any arguments", + )) + } +} diff --git a/rtic-macros/src/syntax/backend/riscv_slic.rs b/rtic-macros/src/syntax/backend/riscv_slic.rs new file mode 100644 index 0000000..2ed8e77 --- /dev/null +++ b/rtic-macros/src/syntax/backend/riscv_slic.rs @@ -0,0 +1,16 @@ +use syn::{ + parse::{Parse, ParseStream}, + Ident, Result, +}; + +#[derive(Debug)] +pub struct BackendArgs { + pub hart_id: Ident, +} + +impl Parse for BackendArgs { + fn parse(input: ParseStream) -> Result { + let hart_id = input.parse()?; + Ok(BackendArgs { hart_id }) + } +} diff --git a/rtic-macros/src/syntax/backend/template.rs b/rtic-macros/src/syntax/backend/template.rs new file mode 100644 index 0000000..6dad114 --- /dev/null +++ b/rtic-macros/src/syntax/backend/template.rs @@ -0,0 +1,15 @@ +use syn::{ + parse::{Parse, ParseStream}, + Result, +}; + +#[derive(Debug)] +pub struct BackendArgs { + // Define your backend-specific input here +} + +impl Parse for BackendArgs { + fn parse(input: ParseStream) -> Result { + todo!("define how to parse your backend-specific arguments") + } +} diff --git a/rtic-macros/src/syntax/parse/app.rs b/rtic-macros/src/syntax/parse/app.rs index efcafbe..469bcb8 100644 --- a/rtic-macros/src/syntax/parse/app.rs +++ b/rtic-macros/src/syntax/parse/app.rs @@ -13,6 +13,7 @@ use crate::syntax::{ App, AppArgs, Dispatcher, Dispatchers, HardwareTask, Idle, IdleArgs, Init, InitArgs, LocalResource, SharedResource, SoftwareTask, }, + backend::BackendArgs, parse::{self as syntax_parse, util}, Either, Map, Set, }; @@ -24,8 +25,10 @@ impl AppArgs { (|input: ParseStream<'_>| -> parse::Result { let mut custom = Set::new(); let mut device = None; + let mut core = true; let mut peripherals = true; let mut dispatchers = Dispatchers::new(); + let mut backend = None; loop { if input.is_empty() { @@ -59,6 +62,17 @@ impl AppArgs { } } + "core" => { + if let Ok(p) = input.parse::() { + core = p.value; + } else { + return Err(parse::Error::new( + ident.span(), + "unexpected argument value; this should be a boolean", + )); + } + } + "peripherals" => { if let Ok(p) = input.parse::() { peripherals = p.value; @@ -113,6 +127,18 @@ impl AppArgs { )); } } + + "backend" => { + if let Ok(p) = input.parse::() { + backend = Some(p); + } else { + return Err(parse::Error::new( + ident.span(), + "unable to parse backend configuration", + )); + } + } + _ => { return Err(parse::Error::new(ident.span(), "unexpected argument")); } @@ -134,8 +160,10 @@ impl AppArgs { Ok(AppArgs { device, + core, peripherals, dispatchers, + backend, }) }) .parse2(tokens) diff --git a/rtic-monotonics/CHANGELOG.md b/rtic-monotonics/CHANGELOG.md index af39143..ef5840f 100644 --- a/rtic-monotonics/CHANGELOG.md +++ b/rtic-monotonics/CHANGELOG.md @@ -9,6 +9,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top! ### Changed +- Tweak `build.rs` to avoid warnings in Nightly 1.78+ - Removed unused `rust-toolchain.toml` ## v1.5.0 - 2024-01-10 diff --git a/rtic/.cargo/config.toml b/rtic/.cargo/config.toml index ddec650..1595860 100644 --- a/rtic/.cargo/config.toml +++ b/rtic/.cargo/config.toml @@ -4,7 +4,13 @@ runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semiho [target.thumbv7m-none-eabi] runner = "qemu-system-arm -cpu cortex-m3 -machine lm3s6965evb -nographic -semihosting-config enable=on,target=native -kernel" -[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +[target.riscv32imc-unknown-none-elf] +runner = "qemu-system-riscv32 -machine sifive_e,revb=true -nographic -semihosting-config enable=on,target=native -kernel" + +[target.riscv32imac-unknown-none-elf] +runner = "qemu-system-riscv32 -machine sifive_e,revb=true -nographic -semihosting-config enable=on,target=native -kernel" + +[target.'cfg(all(any(target_arch = "arm", target_arch = "riscv32"), target_os = "none"))'] rustflags = [ "-C", "link-arg=-Tlink.x", ] diff --git a/rtic/CHANGELOG.md b/rtic/CHANGELOG.md index 0f6e85d..c2cd678 100644 --- a/rtic/CHANGELOG.md +++ b/rtic/CHANGELOG.md @@ -17,6 +17,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top! ### Added +- Unstable support for RISC-V targets compatible with `riscv-slic` - Unstable support for ESP32-C3 ### Fixed diff --git a/rtic/Cargo.toml b/rtic/Cargo.toml index 2fcda6d..f23c650 100644 --- a/rtic/Cargo.toml +++ b/rtic/Cargo.toml @@ -31,11 +31,12 @@ features = ["rtic-macros/test-template"] name = "rtic" [dependencies] +riscv-slic = { git = "https://github.com/romancardenas/riscv-slic.git", rev = "2a91edb", optional = true } esp32c3 = { version = "0.20.0", optional = true} riscv = {version = "0.11.0", optional = true} cortex-m = { version = "0.7.0", optional = true } bare-metal = "1.0.0" -#portable-atomic = { version = "0.3.19" } +# portable-atomic = { version = "0.3.19" } atomic-polyfill = "1" rtic-monotonics = { path = "../rtic-monotonics", version = "1.4.0", optional = true } rtic-macros = { path = "../rtic-macros", version = "=2.1.0" } @@ -43,12 +44,8 @@ rtic-core = "1" critical-section = "1" [dev-dependencies] -heapless = "0.8" lm3s6965 = "0.2" cortex-m-semihosting = "0.5.0" -rtic-time = { path = "../rtic-time" } -rtic-sync = { path = "../rtic-sync" } -rtic-monotonics = { path = "../rtic-monotonics", features = ["cortex-m-systick"] } [dev-dependencies.futures] version = "0.3.26" @@ -71,12 +68,7 @@ thumbv8main-backend = ["cortex-m", "rtic-macros/cortex-m-basepri"] # riscv-clic-backend = ["rtic-macros/riscv-clic"] # riscv-ch32-backend = ["rtic-macros/riscv-ch32"] riscv-esp32c3-backend = ["esp32c3", "riscv", "rtic-macros/riscv-esp32c3"] +riscv-clint-backend = ["riscv", "riscv-slic/clint-backend", "rtic-macros/riscv-slic"] # needed for testing -rtic-uitestv7 = ["thumbv7-backend"] -rtic-uitestv6 = ["thumbv6-backend"] test-critical-section = ["cortex-m/critical-section-single-core", "rtic-monotonics/systick-100hz"] - -# [[example]] -# name = "pool" -# required-features = ["test-critical-section"] diff --git a/rtic/build.rs b/rtic/build.rs index 6a02188..8c87b56 100644 --- a/rtic/build.rs +++ b/rtic/build.rs @@ -1,27 +1,38 @@ use std::env; fn main() { - let target = env::var("TARGET").unwrap(); - - // These targets all have know support for the BASEPRI register. - if target.starts_with("thumbv7m") - | target.starts_with("thumbv7em") - | target.starts_with("thumbv8m.main") - { - println!("cargo:rustc-cfg=feature=\"cortex-m-basepri\""); - } else if target.starts_with("thumbv6m") | target.starts_with("thumbv8m.base") { - println!("cargo:rustc-cfg=feature=\"cortex-m-source-masking\""); - //this should not be this general - //riscv processors differ in interrupt implementation - //even within the same target - //need some other way to discern - } else if target.starts_with("riscv32i") { - println!("cargo:rustc-cfg=feature=\"riscv-esp32c3\""); + // Get the backend feature selected by the user + let mut backends: Vec<_> = env::vars() + .filter_map(|(key, _value)| { + if key.starts_with("CARGO_FEATURE") && key.ends_with("BACKEND") { + // strip 'CARGO_FEATURE_', convert to lowercase, and replace '_' with '-' + Some(key[14..].to_lowercase().replace('_', "-")) + } else { + None + } + }) + .collect(); + if backends.len() > 1 { + panic!("More than one backend feature selected: {:?}", backends); + } + let backend = backends.pop().expect("No backend feature selected."); - // TODO: Add feature here for risc-v targets - // println!("cargo:rustc-cfg=feature=\"riscv\""); - } else if target.starts_with("thumb") || target.starts_with("riscv32") { - panic!("Unknown target '{target}'. Need to update logic in build.rs."); + match backend.as_str() { + "thumbv6-backend" | "thumbv8base-backend" => { + println!("cargo:rustc-cfg=feature=\"cortex-m-source-masking\""); + } + "thumbv7-backend" | "thumbv8main-backend" => { + println!("cargo:rustc-cfg=feature=\"cortex-m-basepri\""); + } + "riscv-esp32c3-backend" => { + println!("cargo:rustc-cfg=feature=\"riscv-esp32c3\""); + } + "riscv-clint-backend" => { + println!("cargo:rustc-cfg=feature=\"riscv-slic\""); + } + _ => { + panic!("Unknown backend feature: {:?}", backend); + } } println!("cargo:rerun-if-changed=build.rs"); diff --git a/rtic/ci/expected/async-channel-done.run b/rtic/ci/expected/async-channel-done.run deleted file mode 100644 index 525962a..0000000 --- a/rtic/ci/expected/async-channel-done.run +++ /dev/null @@ -1,9 +0,0 @@ -Sender 1 sending: 1 -Sender 1 done -Sender 2 sending: 2 -Sender 3 sending: 3 -Receiver got: 1 -Sender 2 done -Receiver got: 2 -Sender 3 done -Receiver got: 3 diff --git a/rtic/ci/expected/async-channel-no-receiver.run b/rtic/ci/expected/async-channel-no-receiver.run deleted file mode 100644 index 34624e1..0000000 --- a/rtic/ci/expected/async-channel-no-receiver.run +++ /dev/null @@ -1 +0,0 @@ -Sender 1 sending: 1 Err(NoReceiver(1)) diff --git a/rtic/ci/expected/async-channel-no-sender.run b/rtic/ci/expected/async-channel-no-sender.run deleted file mode 100644 index 237f2f1..0000000 --- a/rtic/ci/expected/async-channel-no-sender.run +++ /dev/null @@ -1 +0,0 @@ -Receiver got: Err(NoSender) diff --git a/rtic/ci/expected/async-channel-try.run b/rtic/ci/expected/async-channel-try.run deleted file mode 100644 index c3a4092..0000000 --- a/rtic/ci/expected/async-channel-try.run +++ /dev/null @@ -1,2 +0,0 @@ -Sender 1 sending: 1 -Sender 1 try sending: 2 Err(Full(2)) diff --git a/rtic/ci/expected/async-channel.run b/rtic/ci/expected/async-channel.run deleted file mode 100644 index 4e313a1..0000000 --- a/rtic/ci/expected/async-channel.run +++ /dev/null @@ -1,6 +0,0 @@ -Sender 1 sending: 1 -Sender 2 sending: 2 -Sender 3 sending: 3 -Receiver got: 1 -Receiver got: 2 -Receiver got: 3 diff --git a/rtic/ci/expected/async-delay.run b/rtic/ci/expected/async-delay.run deleted file mode 100644 index 61852ab..0000000 --- a/rtic/ci/expected/async-delay.run +++ /dev/null @@ -1,7 +0,0 @@ -init -hello from bar -hello from baz -hello from foo -bye from foo -bye from bar -bye from baz diff --git a/rtic/ci/expected/async-infinite-loop.run b/rtic/ci/expected/async-infinite-loop.run deleted file mode 100644 index f9fd4e4..0000000 --- a/rtic/ci/expected/async-infinite-loop.run +++ /dev/null @@ -1,6 +0,0 @@ -init -hello from async 0 -hello from async 1 -hello from async 2 -hello from async 3 -hello from async 4 diff --git a/rtic/ci/expected/async-task-multiple-prios.run b/rtic/ci/expected/async-task-multiple-prios.run deleted file mode 100644 index 0b42df0..0000000 --- a/rtic/ci/expected/async-task-multiple-prios.run +++ /dev/null @@ -1,6 +0,0 @@ -init -hello from async 3 a 1 -hello from async 4 a 2 -hello from async 1 a 3 -hello from async 2 a 4 -idle diff --git a/rtic/ci/expected/async-task.run b/rtic/ci/expected/async-task.run deleted file mode 100644 index 1f93a4c..0000000 --- a/rtic/ci/expected/async-task.run +++ /dev/null @@ -1,5 +0,0 @@ -init -hello from async2 -hello from async -hello from async with args a: 1, b: 2 -idle diff --git a/rtic/ci/expected/async-timeout.run b/rtic/ci/expected/async-timeout.run deleted file mode 100644 index 6b4c089..0000000 --- a/rtic/ci/expected/async-timeout.run +++ /dev/null @@ -1,16 +0,0 @@ -init -the hal takes a duration of Duration { ticks: 45 } -timeout -the hal takes a duration of Duration { ticks: 45 } -hal returned 5 -the hal takes a duration of Duration { ticks: 45 } -hal returned 5 -now is Instant { ticks: 213 }, timeout at Instant { ticks: 263 } -the hal takes a duration of Duration { ticks: 35 } -hal returned 5 at time Instant { ticks: 249 } -now is Instant { ticks: 313 }, timeout at Instant { ticks: 363 } -the hal takes a duration of Duration { ticks: 45 } -hal returned 5 at time Instant { ticks: 359 } -now is Instant { ticks: 413 }, timeout at Instant { ticks: 463 } -the hal takes a duration of Duration { ticks: 55 } -timeout diff --git a/rtic/ci/expected/big-struct-opt.run b/rtic/ci/expected/big-struct-opt.run deleted file mode 100644 index 7fdef35..0000000 --- a/rtic/ci/expected/big-struct-opt.run +++ /dev/null @@ -1,3 +0,0 @@ -async_task data:[22, 22, 22, 22, 22] -uart0 data:[22, 22, 22, 22, 22] -idle diff --git a/rtic/ci/expected/binds.run b/rtic/ci/expected/binds.run deleted file mode 100644 index f84cff0..0000000 --- a/rtic/ci/expected/binds.run +++ /dev/null @@ -1,4 +0,0 @@ -init -foo called 1 time -idle -foo called 2 times diff --git a/rtic/ci/expected/cancel-reschedule.run b/rtic/ci/expected/cancel-reschedule.run deleted file mode 100644 index 5a94752..0000000 --- a/rtic/ci/expected/cancel-reschedule.run +++ /dev/null @@ -1,3 +0,0 @@ -init -foo -bar diff --git a/rtic/ci/expected/capacity.run b/rtic/ci/expected/capacity.run deleted file mode 100644 index f96815d..0000000 --- a/rtic/ci/expected/capacity.run +++ /dev/null @@ -1,5 +0,0 @@ -foo(0) -foo(1) -foo(2) -foo(3) -bar diff --git a/rtic/ci/expected/cfg-whole-task.run b/rtic/ci/expected/cfg-whole-task.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/common.run b/rtic/ci/expected/common.run deleted file mode 100644 index 4f1d350..0000000 --- a/rtic/ci/expected/common.run +++ /dev/null @@ -1,3 +0,0 @@ -bar: local_to_bar = 1 -foo: local_to_foo = 1 -idle: local_to_idle = 1 diff --git a/rtic/ci/expected/complex.run b/rtic/ci/expected/complex.run deleted file mode 100644 index 5df884d..0000000 --- a/rtic/ci/expected/complex.run +++ /dev/null @@ -1,47 +0,0 @@ -init -idle p0 started -t2 p4 called 1 time -enter lock s4 0 -t3 p4 exit -idle enter lock s3 0 -idle pend t0 -idle pend t1 -idle pend t2 -t2 p4 called 2 times -enter lock s4 1 -t3 p4 exit -idle still in lock s3 0 -t1 p3 called 1 time -t1 enter lock s4 2 -t1 pend t0 -t1 pend t2 -t1 still in lock s4 2 -t2 p4 called 3 times -enter lock s4 2 -t3 p4 exit -t1 p3 exit -t0 p2 called 1 time -t0 p2 exit - -back in idle -enter lock s2 0 -idle pend t0 -idle pend t1 -t1 p3 called 2 times -t1 enter lock s4 3 -t1 pend t0 -t1 pend t2 -t1 still in lock s4 3 -t2 p4 called 4 times -enter lock s4 3 -t3 p4 exit -t1 p3 exit -idle pend t2 -t2 p4 called 5 times -enter lock s4 4 -t3 p4 exit -idle still in lock s2 0 -t0 p2 called 2 times -t0 p2 exit - -idle exit diff --git a/rtic/ci/expected/declared_locals.run b/rtic/ci/expected/declared_locals.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/destructure.run b/rtic/ci/expected/destructure.run deleted file mode 100644 index 25a4b1b..0000000 --- a/rtic/ci/expected/destructure.run +++ /dev/null @@ -1,2 +0,0 @@ -bar: a = 0, b = 1, c = 2 -foo: a = 0, b = 1, c = 2 diff --git a/rtic/ci/expected/executor-size.run b/rtic/ci/expected/executor-size.run deleted file mode 100644 index 2bb0d06..0000000 --- a/rtic/ci/expected/executor-size.run +++ /dev/null @@ -1 +0,0 @@ -init, total executor size = 9 diff --git a/rtic/ci/expected/extern_binds.run b/rtic/ci/expected/extern_binds.run deleted file mode 100644 index 9d925d5..0000000 --- a/rtic/ci/expected/extern_binds.run +++ /dev/null @@ -1,4 +0,0 @@ -init -foo called -idle -foo called diff --git a/rtic/ci/expected/extern_spawn.run b/rtic/ci/expected/extern_spawn.run deleted file mode 100644 index 257cc56..0000000 --- a/rtic/ci/expected/extern_spawn.run +++ /dev/null @@ -1 +0,0 @@ -foo diff --git a/rtic/ci/expected/generics.run b/rtic/ci/expected/generics.run deleted file mode 100644 index fb31731..0000000 --- a/rtic/ci/expected/generics.run +++ /dev/null @@ -1,6 +0,0 @@ -UART1(STATE = 0) -shared: 0 -> 1 -UART0(STATE = 0) -shared: 1 -> 2 -UART1(STATE = 1) -shared: 2 -> 4 diff --git a/rtic/ci/expected/hardware.run b/rtic/ci/expected/hardware.run deleted file mode 100644 index ef00864..0000000 --- a/rtic/ci/expected/hardware.run +++ /dev/null @@ -1,4 +0,0 @@ -init -UART0 called 1 time -idle -UART0 called 2 times diff --git a/rtic/ci/expected/idle-wfi.run b/rtic/ci/expected/idle-wfi.run deleted file mode 100644 index 4307776..0000000 --- a/rtic/ci/expected/idle-wfi.run +++ /dev/null @@ -1,2 +0,0 @@ -init -idle diff --git a/rtic/ci/expected/idle.run b/rtic/ci/expected/idle.run deleted file mode 100644 index 4307776..0000000 --- a/rtic/ci/expected/idle.run +++ /dev/null @@ -1,2 +0,0 @@ -init -idle diff --git a/rtic/ci/expected/init.run b/rtic/ci/expected/init.run deleted file mode 100644 index b1b7161..0000000 --- a/rtic/ci/expected/init.run +++ /dev/null @@ -1 +0,0 @@ -init diff --git a/rtic/ci/expected/locals.run b/rtic/ci/expected/locals.run deleted file mode 100644 index 4f1d350..0000000 --- a/rtic/ci/expected/locals.run +++ /dev/null @@ -1,3 +0,0 @@ -bar: local_to_bar = 1 -foo: local_to_foo = 1 -idle: local_to_idle = 1 diff --git a/rtic/ci/expected/lock-free.run b/rtic/ci/expected/lock-free.run deleted file mode 100644 index 18de0ec..0000000 --- a/rtic/ci/expected/lock-free.run +++ /dev/null @@ -1,2 +0,0 @@ - foo = 1 - bar = 2 diff --git a/rtic/ci/expected/lock.run b/rtic/ci/expected/lock.run deleted file mode 100644 index a987b37..0000000 --- a/rtic/ci/expected/lock.run +++ /dev/null @@ -1,5 +0,0 @@ -A -B - shared = 1 -C -D - shared = 2 -E diff --git a/rtic/ci/expected/message.run b/rtic/ci/expected/message.run deleted file mode 100644 index 11814db..0000000 --- a/rtic/ci/expected/message.run +++ /dev/null @@ -1,6 +0,0 @@ -foo -bar(0) -baz(1, 2) -foo -bar(1) -baz(2, 3) diff --git a/rtic/ci/expected/multilock.run b/rtic/ci/expected/multilock.run deleted file mode 100644 index dd8c1f2..0000000 --- a/rtic/ci/expected/multilock.run +++ /dev/null @@ -1 +0,0 @@ -Multiple locks, s1: 1, s2: 1, s3: 1 diff --git a/rtic/ci/expected/not-sync.run b/rtic/ci/expected/not-sync.run deleted file mode 100644 index cd91476..0000000 --- a/rtic/ci/expected/not-sync.run +++ /dev/null @@ -1,3 +0,0 @@ -init -bar a 13 -foo a 13 diff --git a/rtic/ci/expected/only-shared-access.run b/rtic/ci/expected/only-shared-access.run deleted file mode 100644 index dcc73e6..0000000 --- a/rtic/ci/expected/only-shared-access.run +++ /dev/null @@ -1,2 +0,0 @@ -bar(key = 0xdeadbeef) -foo(key = 0xdeadbeef) diff --git a/rtic/ci/expected/periodic-at.run b/rtic/ci/expected/periodic-at.run deleted file mode 100644 index bf5bb06..0000000 --- a/rtic/ci/expected/periodic-at.run +++ /dev/null @@ -1,4 +0,0 @@ -foo Instant { ticks: 0 } -foo Instant { ticks: 10 } -foo Instant { ticks: 20 } -foo Instant { ticks: 30 } diff --git a/rtic/ci/expected/periodic-at2.run b/rtic/ci/expected/periodic-at2.run deleted file mode 100644 index 6e56421..0000000 --- a/rtic/ci/expected/periodic-at2.run +++ /dev/null @@ -1,7 +0,0 @@ -foo Instant { ticks: 0 } -bar Instant { ticks: 10 } -foo Instant { ticks: 30 } -bar Instant { ticks: 40 } -foo Instant { ticks: 60 } -bar Instant { ticks: 70 } -foo Instant { ticks: 90 } diff --git a/rtic/ci/expected/periodic.run b/rtic/ci/expected/periodic.run deleted file mode 100644 index a1f8944..0000000 --- a/rtic/ci/expected/periodic.run +++ /dev/null @@ -1,4 +0,0 @@ -foo -foo -foo -foo diff --git a/rtic/ci/expected/peripherals-taken.run b/rtic/ci/expected/peripherals-taken.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/pool.run b/rtic/ci/expected/pool.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/preempt.run b/rtic/ci/expected/preempt.run deleted file mode 100644 index 932b2b3..0000000 --- a/rtic/ci/expected/preempt.run +++ /dev/null @@ -1,5 +0,0 @@ -foo - start - baz - start - baz - end - bar -foo - end diff --git a/rtic/ci/expected/prio-inversion.run b/rtic/ci/expected/prio-inversion.run deleted file mode 100644 index 9191436..0000000 --- a/rtic/ci/expected/prio-inversion.run +++ /dev/null @@ -1,6 +0,0 @@ -foo - start -pre baz spawn 0 0 -post baz spawn 0 0 - baz - start - baz - end -foo - end diff --git a/rtic/ci/expected/ramfunc.run b/rtic/ci/expected/ramfunc.run deleted file mode 100644 index 257cc56..0000000 --- a/rtic/ci/expected/ramfunc.run +++ /dev/null @@ -1 +0,0 @@ -foo diff --git a/rtic/ci/expected/ramfunc.run.grep.bar b/rtic/ci/expected/ramfunc.run.grep.bar deleted file mode 100644 index 33e002f..0000000 --- a/rtic/ci/expected/ramfunc.run.grep.bar +++ /dev/null @@ -1 +0,0 @@ -20000000 t ramfunc::bar::h9d6714fe5a3b0c89 diff --git a/rtic/ci/expected/ramfunc.run.grep.foo b/rtic/ci/expected/ramfunc.run.grep.foo deleted file mode 100644 index 44e8822..0000000 --- a/rtic/ci/expected/ramfunc.run.grep.foo +++ /dev/null @@ -1 +0,0 @@ -00000162 t ramfunc::foo::h30e7789b08c08e19 diff --git a/rtic/ci/expected/resource-user-struct.run b/rtic/ci/expected/resource-user-struct.run deleted file mode 100644 index a587a94..0000000 --- a/rtic/ci/expected/resource-user-struct.run +++ /dev/null @@ -1,2 +0,0 @@ -UART0: shared = 1 -UART1: shared = 2 diff --git a/rtic/ci/expected/schedule.run b/rtic/ci/expected/schedule.run deleted file mode 100644 index 1dbd445..0000000 --- a/rtic/ci/expected/schedule.run +++ /dev/null @@ -1,4 +0,0 @@ -init -foo -bar -baz diff --git a/rtic/ci/expected/shared.run b/rtic/ci/expected/shared.run deleted file mode 100644 index 6d3d3e4..0000000 --- a/rtic/ci/expected/shared.run +++ /dev/null @@ -1 +0,0 @@ -received message: 42 diff --git a/rtic/ci/expected/smallest.run b/rtic/ci/expected/smallest.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/spawn.run b/rtic/ci/expected/spawn.run deleted file mode 100644 index 240cd18..0000000 --- a/rtic/ci/expected/spawn.run +++ /dev/null @@ -1,2 +0,0 @@ -init -foo diff --git a/rtic/ci/expected/spawn_arguments.run b/rtic/ci/expected/spawn_arguments.run deleted file mode 100644 index 9085e13..0000000 --- a/rtic/ci/expected/spawn_arguments.run +++ /dev/null @@ -1 +0,0 @@ -foo 1, 1 diff --git a/rtic/ci/expected/spawn_err.run b/rtic/ci/expected/spawn_err.run deleted file mode 100644 index 97c4112..0000000 --- a/rtic/ci/expected/spawn_err.run +++ /dev/null @@ -1,3 +0,0 @@ -init -Cannot spawn a spawned (running) task! -foo diff --git a/rtic/ci/expected/spawn_loop.run b/rtic/ci/expected/spawn_loop.run deleted file mode 100644 index ee6e1e3..0000000 --- a/rtic/ci/expected/spawn_loop.run +++ /dev/null @@ -1,7 +0,0 @@ -init -foo -idle -foo -idle -foo -idle diff --git a/rtic/ci/expected/static.run b/rtic/ci/expected/static.run deleted file mode 100644 index 3d3f46f..0000000 --- a/rtic/ci/expected/static.run +++ /dev/null @@ -1,3 +0,0 @@ -received message: 1 -received message: 2 -received message: 3 diff --git a/rtic/ci/expected/t-binds.run b/rtic/ci/expected/t-binds.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/t-cfg-resources.run b/rtic/ci/expected/t-cfg-resources.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/t-htask-main.run b/rtic/ci/expected/t-htask-main.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/t-idle-main.run b/rtic/ci/expected/t-idle-main.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/t-late-not-send.run b/rtic/ci/expected/t-late-not-send.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/t-schedule.run b/rtic/ci/expected/t-schedule.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/t-spawn.run b/rtic/ci/expected/t-spawn.run deleted file mode 100644 index e69de29..0000000 diff --git a/rtic/ci/expected/task.run b/rtic/ci/expected/task.run deleted file mode 100644 index de45dce..0000000 --- a/rtic/ci/expected/task.run +++ /dev/null @@ -1,5 +0,0 @@ -foo - start -foo - middle -baz -foo - end -bar diff --git a/rtic/ci/expected/zero-prio-task.run b/rtic/ci/expected/zero-prio-task.run deleted file mode 100644 index 123b0f2..0000000 --- a/rtic/ci/expected/zero-prio-task.run +++ /dev/null @@ -1,3 +0,0 @@ -init -hello from async -hello from async2 diff --git a/rtic/examples/async-channel-done.rs b/rtic/examples/async-channel-done.rs deleted file mode 100644 index e9b9887..0000000 --- a/rtic/examples/async-channel-done.rs +++ /dev/null @@ -1,65 +0,0 @@ -//! examples/async-channel-done.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use rtic_sync::{channel::*, make_channel}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - const CAPACITY: usize = 1; - #[init] - fn init(_: init::Context) -> (Shared, Local) { - let (s, r) = make_channel!(u32, CAPACITY); - - receiver::spawn(r).unwrap(); - sender1::spawn(s.clone()).unwrap(); - sender2::spawn(s.clone()).unwrap(); - sender3::spawn(s).unwrap(); - - (Shared {}, Local {}) - } - - #[task] - async fn receiver(_c: receiver::Context, mut receiver: Receiver<'static, u32, CAPACITY>) { - while let Ok(val) = receiver.recv().await { - hprintln!("Receiver got: {}", val); - if val == 3 { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - } - } - - #[task] - async fn sender1(_c: sender1::Context, mut sender: Sender<'static, u32, CAPACITY>) { - hprintln!("Sender 1 sending: 1"); - sender.send(1).await.unwrap(); - hprintln!("Sender 1 done"); - } - - #[task] - async fn sender2(_c: sender2::Context, mut sender: Sender<'static, u32, CAPACITY>) { - hprintln!("Sender 2 sending: 2"); - sender.send(2).await.unwrap(); - hprintln!("Sender 2 done"); - } - - #[task] - async fn sender3(_c: sender3::Context, mut sender: Sender<'static, u32, CAPACITY>) { - hprintln!("Sender 3 sending: 3"); - sender.send(3).await.unwrap(); - hprintln!("Sender 3 done"); - } -} diff --git a/rtic/examples/async-channel-no-receiver.rs b/rtic/examples/async-channel-no-receiver.rs deleted file mode 100644 index 7e416be..0000000 --- a/rtic/examples/async-channel-no-receiver.rs +++ /dev/null @@ -1,37 +0,0 @@ -//! examples/async-channel-no-receiver.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use rtic_sync::{channel::*, make_channel}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - const CAPACITY: usize = 1; - #[init] - fn init(_: init::Context) -> (Shared, Local) { - let (s, _r) = make_channel!(u32, CAPACITY); - - sender1::spawn(s.clone()).unwrap(); - - (Shared {}, Local {}) - } - - #[task] - async fn sender1(_c: sender1::Context, mut sender: Sender<'static, u32, CAPACITY>) { - hprintln!("Sender 1 sending: 1 {:?}", sender.send(1).await); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/rtic/examples/async-channel-no-sender.rs b/rtic/examples/async-channel-no-sender.rs deleted file mode 100644 index c4f043c..0000000 --- a/rtic/examples/async-channel-no-sender.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! examples/async-channel-no-sender.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use rtic_sync::{channel::*, make_channel}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - const CAPACITY: usize = 1; - #[init] - fn init(_: init::Context) -> (Shared, Local) { - let (_s, r) = make_channel!(u32, CAPACITY); - - receiver::spawn(r).unwrap(); - - (Shared {}, Local {}) - } - - #[task] - async fn receiver(_c: receiver::Context, mut receiver: Receiver<'static, u32, CAPACITY>) { - hprintln!("Receiver got: {:?}", receiver.recv().await); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/rtic/examples/async-channel-try.rs b/rtic/examples/async-channel-try.rs deleted file mode 100644 index 92c6ab6..0000000 --- a/rtic/examples/async-channel-try.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! examples/async-channel-try.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use rtic_sync::{channel::*, make_channel}; - - #[shared] - struct Shared {} - - #[local] - struct Local { - sender: Sender<'static, u32, CAPACITY>, - } - - const CAPACITY: usize = 1; - #[init] - fn init(_: init::Context) -> (Shared, Local) { - let (s, r) = make_channel!(u32, CAPACITY); - - receiver::spawn(r).unwrap(); - sender1::spawn(s.clone()).unwrap(); - - (Shared {}, Local { sender: s.clone() }) - } - - #[task] - async fn receiver(_c: receiver::Context, mut receiver: Receiver<'static, u32, CAPACITY>) { - while let Ok(val) = receiver.recv().await { - hprintln!("Receiver got: {}", val); - } - } - - #[task] - async fn sender1(_c: sender1::Context, mut sender: Sender<'static, u32, CAPACITY>) { - hprintln!("Sender 1 sending: 1"); - sender.send(1).await.unwrap(); - hprintln!("Sender 1 try sending: 2 {:?}", sender.try_send(2)); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - - // This interrupt is never triggered, but is used to demonstrate that - // one can (try to) send data into a channel from a hardware task. - #[task(binds = GPIOA, local = [sender])] - fn hw_task(cx: hw_task::Context) { - cx.local.sender.try_send(3).ok(); - } -} diff --git a/rtic/examples/async-channel.rs b/rtic/examples/async-channel.rs deleted file mode 100644 index 642e218..0000000 --- a/rtic/examples/async-channel.rs +++ /dev/null @@ -1,62 +0,0 @@ -//! examples/async-channel.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use rtic_sync::{channel::*, make_channel}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - const CAPACITY: usize = 5; - #[init] - fn init(_: init::Context) -> (Shared, Local) { - let (s, r) = make_channel!(u32, CAPACITY); - - receiver::spawn(r).unwrap(); - sender1::spawn(s.clone()).unwrap(); - sender2::spawn(s.clone()).unwrap(); - sender3::spawn(s).unwrap(); - - (Shared {}, Local {}) - } - - #[task] - async fn receiver(_c: receiver::Context, mut receiver: Receiver<'static, u32, CAPACITY>) { - while let Ok(val) = receiver.recv().await { - hprintln!("Receiver got: {}", val); - if val == 3 { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - } - } - - #[task] - async fn sender1(_c: sender1::Context, mut sender: Sender<'static, u32, CAPACITY>) { - hprintln!("Sender 1 sending: 1"); - sender.send(1).await.unwrap(); - } - - #[task] - async fn sender2(_c: sender2::Context, mut sender: Sender<'static, u32, CAPACITY>) { - hprintln!("Sender 2 sending: 2"); - sender.send(2).await.unwrap(); - } - - #[task] - async fn sender3(_c: sender3::Context, mut sender: Sender<'static, u32, CAPACITY>) { - hprintln!("Sender 3 sending: 3"); - sender.send(3).await.unwrap(); - } -} diff --git a/rtic/examples/async-delay.rs b/rtic/examples/async-delay.rs deleted file mode 100644 index 9ccfc02..0000000 --- a/rtic/examples/async-delay.rs +++ /dev/null @@ -1,58 +0,0 @@ -//! examples/async-delay.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use rtic_monotonics::systick::*; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(cx: init::Context) -> (Shared, Local) { - hprintln!("init"); - - let systick_token = rtic_monotonics::create_systick_token!(); - Systick::start(cx.core.SYST, 12_000_000, systick_token); - - foo::spawn().ok(); - bar::spawn().ok(); - baz::spawn().ok(); - - (Shared {}, Local {}) - } - - #[task] - async fn foo(_cx: foo::Context) { - hprintln!("hello from foo"); - Systick::delay(100.millis()).await; - hprintln!("bye from foo"); - } - - #[task] - async fn bar(_cx: bar::Context) { - hprintln!("hello from bar"); - Systick::delay(200.millis()).await; - hprintln!("bye from bar"); - } - - #[task] - async fn baz(_cx: baz::Context) { - hprintln!("hello from baz"); - Systick::delay(300.millis()).await; - hprintln!("bye from baz"); - - debug::exit(debug::EXIT_SUCCESS); - } -} diff --git a/rtic/examples/async-task-multiple-prios.rs b/rtic/examples/async-task-multiple-prios.rs deleted file mode 100644 index 39b6d60..0000000 --- a/rtic/examples/async-task-multiple-prios.rs +++ /dev/null @@ -1,93 +0,0 @@ -//! examples/async-task-multiple-prios.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -// NOTES: -// -// - Async tasks cannot have `#[lock_free]` resources, as they can interleave and each async -// task can have a mutable reference stored. -// - Spawning an async task equates to it being polled once. - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - a: u32, - b: u32, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - hprintln!("init"); - - async_task1::spawn(1).ok(); - async_task2::spawn().ok(); - async_task3::spawn().ok(); - async_task4::spawn().ok(); - - (Shared { a: 0, b: 0 }, Local {}) - } - - #[idle] - fn idle(_: idle::Context) -> ! { - loop { - hprintln!("idle"); - debug::exit(debug::EXIT_SUCCESS); - } - } - - #[task(priority = 1, shared = [a, b])] - async fn async_task1(mut cx: async_task1::Context, inc: u32) { - hprintln!( - "hello from async 1 a {}", - cx.shared.a.lock(|a| { - *a += inc; - *a - }) - ); - } - - #[task(priority = 1, shared = [a, b])] - async fn async_task2(mut cx: async_task2::Context) { - hprintln!( - "hello from async 2 a {}", - cx.shared.a.lock(|a| { - *a += 1; - *a - }) - ); - } - - #[task(priority = 2, shared = [a, b])] - async fn async_task3(mut cx: async_task3::Context) { - hprintln!( - "hello from async 3 a {}", - cx.shared.a.lock(|a| { - *a += 1; - *a - }) - ); - } - - #[task(priority = 2, shared = [a, b])] - async fn async_task4(mut cx: async_task4::Context) { - hprintln!( - "hello from async 4 a {}", - cx.shared.a.lock(|a| { - *a += 1; - *a - }) - ); - } -} diff --git a/rtic/examples/async-task.rs b/rtic/examples/async-task.rs deleted file mode 100644 index 1867c4d..0000000 --- a/rtic/examples/async-task.rs +++ /dev/null @@ -1,71 +0,0 @@ -//! examples/async-task.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -// NOTES: -// -// - Async tasks cannot have `#[lock_free]` resources, as they can interleave and each async -// task can have a mutable reference stored. -// - Spawning an async task equates to it being polled once. - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - a: u32, - } - - #[local] - struct Local {} - - #[init] - fn init(_cx: init::Context) -> (Shared, Local) { - hprintln!("init"); - - async_task::spawn().unwrap(); - async_task_args::spawn(1, 2).unwrap(); - async_task2::spawn().unwrap(); - - (Shared { a: 0 }, Local {}) - } - - #[idle(shared = [a])] - fn idle(_: idle::Context) -> ! { - loop { - hprintln!("idle"); - debug::exit(debug::EXIT_SUCCESS); - cortex_m::asm::wfi(); // put the MCU in sleep mode until interrupt occurs - } - } - - #[task(binds = UART1, shared = [a])] - fn hw_task(cx: hw_task::Context) { - let hw_task::SharedResources { a: _, .. } = cx.shared; - hprintln!("hello from hw"); - } - - #[task(shared = [a], priority = 1)] - async fn async_task(cx: async_task::Context) { - let async_task::SharedResources { a: _, .. } = cx.shared; - hprintln!("hello from async"); - } - - #[task(priority = 1)] - async fn async_task_args(_cx: async_task_args::Context, a: u32, b: i32) { - hprintln!("hello from async with args a: {}, b: {}", a, b); - } - - #[task(priority = 2, shared = [a])] - async fn async_task2(cx: async_task2::Context) { - let async_task2::SharedResources { a: _, .. } = cx.shared; - hprintln!("hello from async2"); - } -} diff --git a/rtic/examples/async-timeout.rs b/rtic/examples/async-timeout.rs deleted file mode 100644 index e5e129f..0000000 --- a/rtic/examples/async-timeout.rs +++ /dev/null @@ -1,96 +0,0 @@ -//! examples/async-timeout.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use cortex_m_semihosting::{debug, hprintln}; -use panic_semihosting as _; -use rtic_monotonics::systick::*; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)] -mod app { - use super::*; - use futures::{future::FutureExt, select_biased}; - use rtic_monotonics::Monotonic; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - // ANCHOR: init - #[init] - fn init(cx: init::Context) -> (Shared, Local) { - hprintln!("init"); - - let systick_token = rtic_monotonics::create_systick_token!(); - Systick::start(cx.core.SYST, 12_000_000, systick_token); - // ANCHOR_END: init - - foo::spawn().ok(); - - (Shared {}, Local {}) - } - - #[task] - async fn foo(_cx: foo::Context) { - // ANCHOR: select_biased - // Call hal with short relative timeout using `select_biased` - select_biased! { - v = hal_get(1).fuse() => hprintln!("hal returned {}", v), - _ = Systick::delay(200.millis()).fuse() => hprintln!("timeout", ), // this will finish first - } - - // Call hal with long relative timeout using `select_biased` - select_biased! { - v = hal_get(1).fuse() => hprintln!("hal returned {}", v), // hal finish first - _ = Systick::delay(1000.millis()).fuse() => hprintln!("timeout", ), - } - // ANCHOR_END: select_biased - - // ANCHOR: timeout_after_basic - // Call hal with long relative timeout using monotonic `timeout_after` - match Systick::timeout_after(1000.millis(), hal_get(1)).await { - Ok(v) => hprintln!("hal returned {}", v), - _ => hprintln!("timeout"), - } - // ANCHOR_END: timeout_after_basic - - // ANCHOR: timeout_at_basic - // get the current time instance - let mut instant = Systick::now(); - - // do this 3 times - for n in 0..3 { - // absolute point in time without drift - instant += 1000.millis(); - Systick::delay_until(instant).await; - - // absolute point in time for timeout - let timeout = instant + 500.millis(); - hprintln!("now is {:?}, timeout at {:?}", Systick::now(), timeout); - - match Systick::timeout_at(timeout, hal_get(n)).await { - Ok(v) => hprintln!("hal returned {} at time {:?}", v, Systick::now()), - _ => hprintln!("timeout"), - } - } - // ANCHOR_END: timeout_at_basic - - debug::exit(debug::EXIT_SUCCESS); - } -} - -// Emulate some hal -async fn hal_get(n: u32) -> u32 { - // emulate some delay time dependent on n - let d = 350.millis() + n * 100.millis(); - hprintln!("the hal takes a duration of {:?}", d); - Systick::delay(d).await; - // emulate some return value - 5 -} diff --git a/rtic/examples/big-struct-opt.rs b/rtic/examples/big-struct-opt.rs deleted file mode 100644 index 109cc5d..0000000 --- a/rtic/examples/big-struct-opt.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! examples/big-struct-opt.rs -//! -//! Example on how to initialize a large struct without needing to copy it via `LateResources`, -//! effectively saving stack space needed for the copies. - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -/// Some big struct -pub struct BigStruct { - /// Big content - pub data: [u8; 2048], -} - -impl BigStruct { - fn new() -> Self { - BigStruct { data: [22; 2048] } - } -} - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use super::BigStruct; - use core::mem::MaybeUninit; - use cortex_m_semihosting::{debug, hprintln}; - use lm3s6965::Interrupt; - - #[shared] - struct Shared { - big_struct: &'static mut BigStruct, - } - - #[local] - struct Local {} - - #[init(local = [bs: MaybeUninit = MaybeUninit::uninit()])] - fn init(cx: init::Context) -> (Shared, Local) { - let big_struct = unsafe { - // write directly into the static storage - cx.local.bs.as_mut_ptr().write(BigStruct::new()); - &mut *cx.local.bs.as_mut_ptr() - }; - - rtic::pend(Interrupt::UART0); - async_task::spawn().unwrap(); - ( - Shared { - // assign the reference so we can use the resource - big_struct, - }, - Local {}, - ) - } - - #[idle] - fn idle(_: idle::Context) -> ! { - loop { - hprintln!("idle"); - debug::exit(debug::EXIT_SUCCESS); - } - } - - #[task(binds = UART0, shared = [big_struct])] - fn uart0(mut cx: uart0::Context) { - cx.shared - .big_struct - .lock(|b| hprintln!("uart0 data:{:?}", &b.data[0..5])); - } - - #[task(shared = [big_struct], priority = 2)] - async fn async_task(mut cx: async_task::Context) { - cx.shared - .big_struct - .lock(|b| hprintln!("async_task data:{:?}", &b.data[0..5])); - } -} diff --git a/rtic/examples/binds.rs b/rtic/examples/binds.rs deleted file mode 100644 index b101d54..0000000 --- a/rtic/examples/binds.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! examples/binds.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -// `examples/interrupt.rs` rewritten to use `binds` -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use lm3s6965::Interrupt; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - rtic::pend(Interrupt::UART0); - - hprintln!("init"); - - (Shared {}, Local {}) - } - - #[idle] - fn idle(_: idle::Context) -> ! { - hprintln!("idle"); - - rtic::pend(Interrupt::UART0); - - loop { - cortex_m::asm::nop(); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - } - - #[task(binds = UART0, local = [times: u32 = 0])] - fn foo(cx: foo::Context) { - *cx.local.times += 1; - - hprintln!( - "foo called {} time{}", - *cx.local.times, - if *cx.local.times > 1 { "s" } else { "" } - ); - } -} diff --git a/rtic/examples/common.rs b/rtic/examples/common.rs deleted file mode 100644 index 7f68739..0000000 --- a/rtic/examples/common.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! examples/common.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [UART0, UART1])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local { - local_to_foo: i64, - local_to_bar: i64, - local_to_idle: i64, - } - - // `#[init]` cannot access locals from the `#[local]` struct as they are initialized here. - #[init] - fn init(_: init::Context) -> (Shared, Local) { - foo::spawn().unwrap(); - bar::spawn().unwrap(); - - ( - Shared {}, - // initial values for the `#[local]` resources - Local { - local_to_foo: 0, - local_to_bar: 0, - local_to_idle: 0, - }, - ) - } - - // `local_to_idle` can only be accessed from this context - #[idle(local = [local_to_idle])] - fn idle(cx: idle::Context) -> ! { - let local_to_idle = cx.local.local_to_idle; - *local_to_idle += 1; - - hprintln!("idle: local_to_idle = {}", local_to_idle); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - - // error: no `local_to_foo` field in `idle::LocalResources` - // _cx.local.local_to_foo += 1; - - // error: no `local_to_bar` field in `idle::LocalResources` - // _cx.local.local_to_bar += 1; - - loop { - cortex_m::asm::nop(); - } - } - - // `local_to_foo` can only be accessed from this context - #[task(local = [local_to_foo], priority = 1)] - async fn foo(cx: foo::Context) { - let local_to_foo = cx.local.local_to_foo; - *local_to_foo += 1; - - // error: no `local_to_bar` field in `foo::LocalResources` - // cx.local.local_to_bar += 1; - - hprintln!("foo: local_to_foo = {}", local_to_foo); - } - - // `local_to_bar` can only be accessed from this context - #[task(local = [local_to_bar], priority = 1)] - async fn bar(cx: bar::Context) { - let local_to_bar = cx.local.local_to_bar; - *local_to_bar += 1; - - // error: no `local_to_foo` field in `bar::LocalResources` - // cx.local.local_to_foo += 1; - - hprintln!("bar: local_to_bar = {}", local_to_bar); - } -} diff --git a/rtic/examples/complex.rs b/rtic/examples/complex.rs deleted file mode 100644 index a4fe659..0000000 --- a/rtic/examples/complex.rs +++ /dev/null @@ -1,129 +0,0 @@ -//! examples/complex.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - - use cortex_m_semihosting::{debug, hprintln}; - use lm3s6965::Interrupt; - - #[shared] - struct Shared { - s2: u32, // shared with ceiling 2 - s3: u32, // shared with ceiling 3 - s4: u32, // shared with ceiling 4 - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - hprintln!("init"); - - ( - Shared { - s2: 0, - s3: 0, - s4: 0, - }, - Local {}, - ) - } - - #[idle(shared = [s2, s3])] - fn idle(mut cx: idle::Context) -> ! { - hprintln!("idle p0 started"); - rtic::pend(Interrupt::GPIOC); - cx.shared.s3.lock(|s| { - hprintln!("idle enter lock s3 {}", s); - hprintln!("idle pend t0"); - rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 3 - hprintln!("idle pend t1"); - rtic::pend(Interrupt::GPIOB); // t1 p3, with shared ceiling 3 - hprintln!("idle pend t2"); - rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing - hprintln!("idle still in lock s3 {}", s); - }); - hprintln!("\nback in idle"); - - cx.shared.s2.lock(|s| { - hprintln!("enter lock s2 {}", s); - hprintln!("idle pend t0"); - rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 2 - hprintln!("idle pend t1"); - rtic::pend(Interrupt::GPIOB); // t1 p3, no sharing - hprintln!("idle pend t2"); - rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing - hprintln!("idle still in lock s2 {}", s); - }); - hprintln!("\nidle exit"); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - - loop { - cortex_m::asm::nop(); - } - } - - #[task(binds = GPIOA, priority = 2, local = [times: u32 = 0], shared = [s2, s3])] - fn t0(cx: t0::Context) { - // Safe access to local `static mut` variable - *cx.local.times += 1; - - hprintln!( - "t0 p2 called {} time{}", - *cx.local.times, - if *cx.local.times > 1 { "s" } else { "" } - ); - hprintln!("t0 p2 exit"); - } - - #[task(binds = GPIOB, priority = 3, local = [times: u32 = 0], shared = [s3, s4])] - fn t1(mut cx: t1::Context) { - // Safe access to local `static mut` variable - *cx.local.times += 1; - - hprintln!( - "t1 p3 called {} time{}", - *cx.local.times, - if *cx.local.times > 1 { "s" } else { "" } - ); - - cx.shared.s4.lock(|s| { - hprintln!("t1 enter lock s4 {}", s); - hprintln!("t1 pend t0"); - rtic::pend(Interrupt::GPIOA); // t0 p2, with shared ceiling 2 - hprintln!("t1 pend t2"); - rtic::pend(Interrupt::GPIOC); // t2 p4, no sharing - hprintln!("t1 still in lock s4 {}", s); - }); - - hprintln!("t1 p3 exit"); - } - - #[task(binds = GPIOC, priority = 4, local = [times: u32 = 0], shared = [s4])] - fn t2(mut cx: t2::Context) { - // Safe access to local `static mut` variable - *cx.local.times += 1; - - hprintln!( - "t2 p4 called {} time{}", - *cx.local.times, - if *cx.local.times > 1 { "s" } else { "" } - ); - - cx.shared.s4.lock(|s| { - hprintln!("enter lock s4 {}", s); - *s += 1; - }); - hprintln!("t3 p4 exit"); - } -} diff --git a/rtic/examples/declared_locals.rs b/rtic/examples/declared_locals.rs deleted file mode 100644 index b1bb9f4..0000000 --- a/rtic/examples/declared_locals.rs +++ /dev/null @@ -1,47 +0,0 @@ -//! examples/declared_locals.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::debug; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init(local = [a: u32 = 0])] - fn init(cx: init::Context) -> (Shared, Local) { - // Locals in `#[init]` have 'static lifetime - let _a: &'static mut u32 = cx.local.a; - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - - (Shared {}, Local {}) - } - - #[idle(local = [a: u32 = 0])] - fn idle(cx: idle::Context) -> ! { - // Locals in `#[idle]` have 'static lifetime - let _a: &'static mut u32 = cx.local.a; - - loop {} - } - - #[task(binds = UART0, local = [a: u32 = 0])] - fn foo(cx: foo::Context) { - // Locals in `#[task]`s have a local lifetime - let _a: &mut u32 = cx.local.a; - - // error: explicit lifetime required in the type of `cx` - // let _a: &'static mut u32 = cx.local.a; - } -} diff --git a/rtic/examples/destructure.rs b/rtic/examples/destructure.rs deleted file mode 100644 index ac35187..0000000 --- a/rtic/examples/destructure.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! examples/destructure.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [UART0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - a: u32, - b: u32, - c: u32, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - foo::spawn().unwrap(); - bar::spawn().unwrap(); - - (Shared { a: 0, b: 1, c: 2 }, Local {}) - } - - #[idle] - fn idle(_: idle::Context) -> ! { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - loop {} - } - - // Direct destructure - #[task(shared = [&a, &b, &c], priority = 1)] - async fn foo(cx: foo::Context) { - let a = cx.shared.a; - let b = cx.shared.b; - let c = cx.shared.c; - - hprintln!("foo: a = {}, b = {}, c = {}", a, b, c); - } - - // De-structure-ing syntax - #[task(shared = [&a, &b, &c], priority = 1)] - async fn bar(cx: bar::Context) { - let bar::SharedResources { a, b, c, .. } = cx.shared; - - hprintln!("bar: a = {}, b = {}, c = {}", a, b, c); - } -} diff --git a/rtic/examples/executor-size.rs b/rtic/examples/executor-size.rs deleted file mode 100644 index d825729..0000000 --- a/rtic/examples/executor-size.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! examples/executor-size.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0, UART0], peripherals = true)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(cx: init::Context) -> (Shared, Local) { - hprintln!("init, total executor size = {}", cx.executors_size); - - foo::spawn().ok(); - bar::spawn().ok(); - baz::spawn().ok(); - - (Shared {}, Local {}) - } - - #[task] - async fn foo(_cx: foo::Context) {} - - #[task] - async fn bar(_cx: bar::Context) {} - - #[task] - async fn baz(_cx: baz::Context) { - debug::exit(debug::EXIT_SUCCESS); - } -} diff --git a/rtic/examples/extern_binds.rs b/rtic/examples/extern_binds.rs deleted file mode 100644 index 45939d2..0000000 --- a/rtic/examples/extern_binds.rs +++ /dev/null @@ -1,59 +0,0 @@ -//! examples/extern_binds.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use cortex_m_semihosting::{debug, hprintln}; -use lm3s6965::Interrupt; -use panic_semihosting as _; - -// Free function implementing `init`. -fn init(_: app::init::Context) -> (app::Shared, app::Local) { - rtic::pend(Interrupt::UART0); - - hprintln!("init"); - - (app::Shared {}, app::Local {}) -} - -// Free function implementing `idle`. -fn idle(_: app::idle::Context) -> ! { - hprintln!("idle"); - - rtic::pend(Interrupt::UART0); - - loop { - cortex_m::asm::nop(); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} - -// Free function implementing the interrupt bound task `foo`. -fn foo(_: app::foo::Context) { - hprintln!("foo called"); -} - -#[rtic::app(device = lm3s6965)] -mod app { - use crate::{foo, idle, init}; - - #[shared] - pub struct Shared {} - - #[local] - pub struct Local {} - - extern "Rust" { - #[init] - fn init(_: init::Context) -> (Shared, Local); - - #[idle] - fn idle(_: idle::Context) -> !; - - #[task(binds = UART0)] - fn foo(_: foo::Context); - } -} diff --git a/rtic/examples/extern_spawn.rs b/rtic/examples/extern_spawn.rs deleted file mode 100644 index 7f68b42..0000000 --- a/rtic/examples/extern_spawn.rs +++ /dev/null @@ -1,40 +0,0 @@ -//! examples/extern_spawn.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use cortex_m_semihosting::{debug, hprintln}; -use panic_semihosting as _; - -// Free function implementing the spawnable task `foo`. -// Notice, you need to indicate an anonymous lifetime <'a_> -async fn foo(_c: app::foo::Context<'_>) { - hprintln!("foo"); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator -} - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use crate::foo; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - foo::spawn().unwrap(); - - (Shared {}, Local {}) - } - - extern "Rust" { - #[task()] - async fn foo(_c: foo::Context); - } -} diff --git a/rtic/examples/generics.rs b/rtic/examples/generics.rs deleted file mode 100644 index dd042a3..0000000 --- a/rtic/examples/generics.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! examples/generics.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use cortex_m_semihosting::hprintln; -use panic_semihosting as _; -use rtic::Mutex; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use lm3s6965::Interrupt; - - #[shared] - struct Shared { - shared: u32, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - rtic::pend(Interrupt::UART0); - rtic::pend(Interrupt::UART1); - - (Shared { shared: 0 }, Local {}) - } - - #[task(binds = UART0, shared = [shared], local = [state: u32 = 0])] - fn uart0(c: uart0::Context) { - hprintln!("UART0(STATE = {})", *c.local.state); - - // second argument has type `shared::shared` - super::advance(c.local.state, c.shared.shared); - - rtic::pend(Interrupt::UART1); - - cortex_m::asm::nop(); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - - #[task(binds = UART1, priority = 2, shared = [shared], local = [state: u32 = 0])] - fn uart1(c: uart1::Context) { - hprintln!("UART1(STATE = {})", *c.local.state); - - // second argument has type `shared::shared` - super::advance(c.local.state, c.shared.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) { - *state += 1; - - let (old, new) = shared.lock(|shared: &mut u32| { - let old = *shared; - *shared += *state; - (old, *shared) - }); - - hprintln!("shared: {} -> {}", old, new); -} diff --git a/rtic/examples/hardware.rs b/rtic/examples/hardware.rs deleted file mode 100644 index 3bd62b6..0000000 --- a/rtic/examples/hardware.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! examples/hardware.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use lm3s6965::Interrupt; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - // 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"); - - (Shared {}, Local {}) - } - - #[idle] - fn idle(_: idle::Context) -> ! { - // interrupts are enabled again; the `UART0` handler runs at this point - - hprintln!("idle"); - - // Some backends provide a manual way of pending an - // interrupt. - rtic::pend(Interrupt::UART0); - - loop { - cortex_m::asm::nop(); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - } - - #[task(binds = UART0, local = [times: u32 = 0])] - fn uart0(cx: uart0::Context) { - // Safe access to local `static mut` variable - *cx.local.times += 1; - - hprintln!( - "UART0 called {} time{}", - *cx.local.times, - if *cx.local.times > 1 { "s" } else { "" } - ); - } -} diff --git a/rtic/examples/idle-wfi.rs b/rtic/examples/idle-wfi.rs deleted file mode 100644 index 72aaa95..0000000 --- a/rtic/examples/idle-wfi.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! examples/idle-wfi.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(mut cx: init::Context) -> (Shared, Local) { - hprintln!("init"); - - // Set the ARM SLEEPONEXIT bit to go to sleep after handling interrupts - // See https://developer.arm.com/docs/100737/0100/power-management/sleep-mode/sleep-on-exit-bit - cx.core.SCB.set_sleepdeep(); - - (Shared {}, Local {}) - } - - #[idle(local = [x: u32 = 0])] - fn idle(cx: idle::Context) -> ! { - // Locals in idle have lifetime 'static - let _x: &'static mut u32 = cx.local.x; - - hprintln!("idle"); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - - loop { - // Now Wait For Interrupt is used instead of a busy-wait loop - // to allow MCU to sleep between interrupts - // https://developer.arm.com/documentation/ddi0406/c/Application-Level-Architecture/Instruction-Details/Alphabetical-list-of-instructions/WFI - rtic::export::wfi() - } - } -} diff --git a/rtic/examples/idle.rs b/rtic/examples/idle.rs deleted file mode 100644 index 4149818..0000000 --- a/rtic/examples/idle.rs +++ /dev/null @@ -1,41 +0,0 @@ -//! examples/idle.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - hprintln!("init"); - - (Shared {}, Local {}) - } - - #[idle(local = [x: u32 = 0])] - fn idle(cx: idle::Context) -> ! { - // Locals in idle have lifetime 'static - let _x: &'static mut u32 = cx.local.x; - - hprintln!("idle"); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - - loop { - cortex_m::asm::nop(); - } - } -} diff --git a/rtic/examples/init.rs b/rtic/examples/init.rs deleted file mode 100644 index 634d309..0000000 --- a/rtic/examples/init.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! examples/init.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, peripherals = true)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init(local = [x: u32 = 0])] - fn init(cx: init::Context) -> (Shared, Local) { - // Cortex-M peripherals - let _core: cortex_m::Peripherals = cx.core; - - // Device specific peripherals - let _device: lm3s6965::Peripherals = cx.device; - - // Locals in `init` have 'static lifetime - let _x: &'static mut u32 = cx.local.x; - - // Access to the critical section token, - // to indicate that this is a critical section - let _cs_token: bare_metal::CriticalSection = cx.cs; - - hprintln!("init"); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - - (Shared {}, Local {}) - } -} diff --git a/rtic/examples/locals.rs b/rtic/examples/locals.rs deleted file mode 100644 index 5d5e246..0000000 --- a/rtic/examples/locals.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! examples/locals.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [UART0, UART1])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local { - local_to_foo: i64, - local_to_bar: i64, - local_to_idle: i64, - } - - // `#[init]` cannot access locals from the `#[local]` struct as they are initialized here. - #[init] - fn init(_: init::Context) -> (Shared, Local) { - foo::spawn().unwrap(); - bar::spawn().unwrap(); - - ( - Shared {}, - // initial values for the `#[local]` resources - Local { - local_to_foo: 0, - local_to_bar: 0, - local_to_idle: 0, - }, - ) - } - - // `local_to_idle` can only be accessed from this context - #[idle(local = [local_to_idle])] - fn idle(cx: idle::Context) -> ! { - let local_to_idle = cx.local.local_to_idle; - *local_to_idle += 1; - - hprintln!("idle: local_to_idle = {}", local_to_idle); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - - // error: no `local_to_foo` field in `idle::LocalResources` - // _cx.local.local_to_foo += 1; - - // error: no `local_to_bar` field in `idle::LocalResources` - // _cx.local.local_to_bar += 1; - - loop { - cortex_m::asm::nop(); - } - } - - // `local_to_foo` can only be accessed from this context - #[task(local = [local_to_foo], priority = 1)] - async fn foo(cx: foo::Context) { - let local_to_foo = cx.local.local_to_foo; - *local_to_foo += 1; - - // error: no `local_to_bar` field in `foo::LocalResources` - // cx.local.local_to_bar += 1; - - hprintln!("foo: local_to_foo = {}", local_to_foo); - } - - // `local_to_bar` can only be accessed from this context - #[task(local = [local_to_bar], priority = 1)] - async fn bar(cx: bar::Context) { - let local_to_bar = cx.local.local_to_bar; - *local_to_bar += 1; - - // error: no `local_to_foo` field in `bar::LocalResources` - // cx.local.local_to_foo += 1; - - hprintln!("bar: local_to_bar = {}", local_to_bar); - } -} diff --git a/rtic/examples/lock-free.rs b/rtic/examples/lock-free.rs deleted file mode 100644 index c9d2ab0..0000000 --- a/rtic/examples/lock-free.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! examples/lock-free.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use lm3s6965::Interrupt; - - #[shared] - struct Shared { - #[lock_free] // <- lock-free shared resource - counter: u64, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - rtic::pend(Interrupt::UART0); - - (Shared { counter: 0 }, Local {}) - } - - #[task(binds = UART0, shared = [counter])] // <- same priority - fn foo(c: foo::Context) { - rtic::pend(Interrupt::UART1); - - *c.shared.counter += 1; // <- no lock API required - let counter = *c.shared.counter; - hprintln!(" foo = {}", counter); - } - - #[task(binds = UART1, shared = [counter])] // <- same priority - fn bar(c: bar::Context) { - rtic::pend(Interrupt::UART0); - *c.shared.counter += 1; // <- no lock API required - let counter = *c.shared.counter; - hprintln!(" bar = {}", counter); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/rtic/examples/lock.rs b/rtic/examples/lock.rs deleted file mode 100644 index 091a1b0..0000000 --- a/rtic/examples/lock.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! examples/lock.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [GPIOA, GPIOB, GPIOC])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - shared: u32, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - foo::spawn().unwrap(); - - (Shared { shared: 0 }, Local {}) - } - - // when omitted priority is assumed to be `1` - #[task(shared = [shared])] - async fn foo(mut c: foo::Context) { - hprintln!("A"); - - // the lower priority task requires a critical section to access the data - c.shared.shared.lock(|shared| { - // data can only be modified within this critical section (closure) - *shared += 1; - - // bar will *not* run right now due to the critical section - bar::spawn().unwrap(); - - hprintln!("B - shared = {}", *shared); - - // baz does not contend for `shared` so it's allowed to run now - baz::spawn().unwrap(); - }); - - // critical section is over: bar can now start - - hprintln!("E"); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - - #[task(priority = 2, shared = [shared])] - async fn bar(mut c: bar::Context) { - // the higher priority task does still need a critical section - let shared = c.shared.shared.lock(|shared| { - *shared += 1; - - *shared - }); - - hprintln!("D - shared = {}", shared); - } - - #[task(priority = 3)] - async fn baz(_: baz::Context) { - hprintln!("C"); - } -} diff --git a/rtic/examples/multilock.rs b/rtic/examples/multilock.rs deleted file mode 100644 index 77245ae..0000000 --- a/rtic/examples/multilock.rs +++ /dev/null @@ -1,56 +0,0 @@ -//! examples/mutlilock.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [GPIOA])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - shared1: u32, - shared2: u32, - shared3: u32, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - locks::spawn().unwrap(); - - ( - Shared { - shared1: 0, - shared2: 0, - shared3: 0, - }, - Local {}, - ) - } - - // when omitted priority is assumed to be `1` - #[task(shared = [shared1, shared2, shared3])] - async fn locks(c: locks::Context) { - let s1 = c.shared.shared1; - let s2 = c.shared.shared2; - let s3 = c.shared.shared3; - - (s1, s2, s3).lock(|s1, s2, s3| { - *s1 += 1; - *s2 += 1; - *s3 += 1; - - hprintln!("Multiple locks, s1: {}, s2: {}, s3: {}", *s1, *s2, *s3); - }); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/rtic/examples/not-sync.rs b/rtic/examples/not-sync.rs deleted file mode 100644 index 09ba77e..0000000 --- a/rtic/examples/not-sync.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! `examples/not-sync.rs` - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(missing_docs)] - -use core::marker::PhantomData; -use panic_semihosting as _; - -/// Not sync -pub struct NotSync { - _0: PhantomData<*const ()>, - data: u32, -} - -unsafe impl Send for NotSync {} - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use super::NotSync; - use core::marker::PhantomData; - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - shared: NotSync, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - hprintln!("init"); - - foo::spawn().unwrap(); - bar::spawn().unwrap(); - ( - Shared { - shared: NotSync { - _0: PhantomData, - data: 13, - }, - }, - Local {}, - ) - } - - #[idle] - fn idle(_: idle::Context) -> ! { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - loop {} - } - - #[task(shared = [&shared], priority = 1)] - async fn foo(c: foo::Context) { - let shared: &NotSync = c.shared.shared; - hprintln!("foo a {}", shared.data); - } - - #[task(shared = [&shared], priority = 1)] - async fn bar(c: bar::Context) { - let shared: &NotSync = c.shared.shared; - hprintln!("bar a {}", shared.data); - } -} diff --git a/rtic/examples/only-shared-access.rs b/rtic/examples/only-shared-access.rs deleted file mode 100644 index c83dca5..0000000 --- a/rtic/examples/only-shared-access.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! examples/only-shared-access.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [UART0, UART1])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - key: u32, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - foo::spawn().unwrap(); - bar::spawn().unwrap(); - - (Shared { key: 0xdeadbeef }, Local {}) - } - - #[task(shared = [&key])] - async fn foo(cx: foo::Context) { - let key: &u32 = cx.shared.key; - hprintln!("foo(key = {:#x})", key); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - - #[task(priority = 2, shared = [&key])] - async fn bar(cx: bar::Context) { - hprintln!("bar(key = {:#x})", cx.shared.key); - } -} diff --git a/rtic/examples/peripherals-taken.rs b/rtic/examples/peripherals-taken.rs deleted file mode 100644 index 2f63001..0000000 --- a/rtic/examples/peripherals-taken.rs +++ /dev/null @@ -1,28 +0,0 @@ -//! examples/peripherals-taken.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::debug; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - assert!(cortex_m::Peripherals::take().is_none()); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - - (Shared {}, Local {}) - } -} diff --git a/rtic/examples/pool.rs_old b/rtic/examples/pool.rs_old deleted file mode 100644 index b399202..0000000 --- a/rtic/examples/pool.rs_old +++ /dev/null @@ -1,69 +0,0 @@ -//! examples/pool.rs - -#![no_main] -#![no_std] -#![deny(warnings)] - -use heapless::{ - pool, - pool::singleton::{Box, Pool}, -}; -use panic_semihosting as _; -use rtic::app; - -// Declare a pool of 128-byte memory blocks -pool!(P: [u8; 128]); - -#[app(device = lm3s6965, dispatchers = [SSI0, QEI0])] -mod app { - use crate::{Box, Pool}; - use cortex_m_semihosting::debug; - use lm3s6965::Interrupt; - - // Import the memory pool into scope - use super::P; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init(local = [memory: [u8; 512] = [0; 512]])] - fn init(cx: init::Context) -> (Shared, Local) { - // Increase the capacity of the memory pool by ~4 - P::grow(cx.local.memory); - - rtic::pend(Interrupt::I2C0); - - (Shared {}, Local {}) - } - - #[task(binds = I2C0, priority = 2)] - fn i2c0(_: i2c0::Context) { - // claim a memory block, initialize it and .. - let x = P::alloc().unwrap().init([0u8; 128]); - - // .. send it to the `foo` task - foo::spawn(x).ok().unwrap(); - - // send another block to the task `bar` - bar::spawn(P::alloc().unwrap().init([0u8; 128])) - .ok() - .unwrap(); - } - - #[task] - async fn foo(_: foo::Context, _x: Box

) { - // explicitly return the block to the pool - drop(_x); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - - #[task(priority = 2)] - async fn bar(_: bar::Context, _x: Box

) { - // this is done automatically so we can omit the call to `drop` - // drop(_x); - } -} diff --git a/rtic/examples/preempt.rs b/rtic/examples/preempt.rs deleted file mode 100644 index 62c67dc..0000000 --- a/rtic/examples/preempt.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! examples/preempt.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; -use rtic::app; - -#[app(device = lm3s6965, dispatchers = [SSI0, QEI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - foo::spawn().unwrap(); - - (Shared {}, Local {}) - } - - #[task(priority = 1)] - async fn foo(_: foo::Context) { - hprintln!("foo - start"); - baz::spawn().unwrap(); - hprintln!("foo - end"); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - - #[task(priority = 2)] - async fn bar(_: bar::Context) { - hprintln!(" bar"); - } - - #[task(priority = 2)] - async fn baz(_: baz::Context) { - hprintln!(" baz - start"); - bar::spawn().unwrap(); - hprintln!(" baz - end"); - } -} diff --git a/rtic/examples/prio-inversion.rs b/rtic/examples/prio-inversion.rs deleted file mode 100644 index 36dcbe2..0000000 --- a/rtic/examples/prio-inversion.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! examples/prio-inversion.rs -//! -//! Here we test to make sure we don't have priority inversion. - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; -use rtic::app; - -// t1 p1 use b, a -// t2 p2 use a -// t3 p3 -// t4 p4 use b -// -// so t1 start , take b take a, pend t3 -// t3 should not start -// try to see if it starts, IT SHOULD NOT - -#[app(device = lm3s6965, dispatchers = [SSI0, QEI0, GPIOA, GPIOB])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - a: u32, - b: u32, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - foo::spawn().unwrap(); - - (Shared { a: 0, b: 0 }, Local {}) - } - - #[task(priority = 1, shared = [a, b])] - async fn foo(cx: foo::Context) { - let foo::SharedResources { mut a, mut b, .. } = cx.shared; - - hprintln!("foo - start"); - - // basepri = 0 - b.lock(|b| { - // basepri = max(basepri = 0, ceil(b) = 4) = 4 - a.lock(|a| { - // basepri = max(basepri = 4, ceil(a) = 2) = 4 - - hprintln!("pre baz spawn {} {}", a, b); - - // This spawn should be blocked as prio(baz) = 3 - baz::spawn().unwrap(); - - hprintln!("post baz spawn {} {}", a, b); - }); - // basepri = 4 - }); - // basepri = 0 - - hprintln!("foo - end"); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - - #[task(priority = 2, shared = [a])] - async fn bar(_: bar::Context) { - hprintln!(" bar"); - } - - #[task(priority = 3)] - async fn baz(_: baz::Context) { - hprintln!(" baz - start"); - hprintln!(" baz - end"); - } - - #[task(priority = 4, shared = [b])] - async fn pow(_: pow::Context) { - hprintln!(" pow - start"); - hprintln!(" pow - end"); - } -} diff --git a/rtic/examples/ramfunc.rs b/rtic/examples/ramfunc.rs deleted file mode 100644 index d072ecb..0000000 --- a/rtic/examples/ramfunc.rs +++ /dev/null @@ -1,49 +0,0 @@ -//! examples/ramfunc.rs -//! TODO: verify that ram-sections are properly used - -#![no_main] -#![no_std] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app( - device = lm3s6965, - dispatchers = [ - UART0, - #[link_section = ".data.UART1"] - UART1 - ]) -] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - foo::spawn().unwrap(); - - (Shared {}, Local {}) - } - - #[inline(never)] - #[task] - async fn foo(_: foo::Context) { - hprintln!("foo"); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - - // run this task from RAM - #[inline(never)] - #[link_section = ".data.bar"] - #[task(priority = 2)] - async fn bar(_: bar::Context) { - foo::spawn().unwrap(); - } -} diff --git a/rtic/examples/resource-user-struct.rs b/rtic/examples/resource-user-struct.rs deleted file mode 100644 index cad42d7..0000000 --- a/rtic/examples/resource-user-struct.rs +++ /dev/null @@ -1,72 +0,0 @@ -//! examples/resource.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use lm3s6965::Interrupt; - - #[shared] - struct Shared { - // A resource - shared: u32, - } - - // Should not collide with the struct above - #[allow(dead_code)] - struct Shared2 { - // A resource - shared: u32, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - rtic::pend(Interrupt::UART0); - rtic::pend(Interrupt::UART1); - - (Shared { shared: 0 }, Local {}) - } - - // `shared` cannot be accessed from this context - #[idle] - fn idle(_cx: idle::Context) -> ! { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - - // error: no `shared` field in `idle::Context` - // _cx.shared.shared += 1; - - loop {} - } - - // `shared` can be accessed from this context - #[task(binds = UART0, shared = [shared])] - fn uart0(mut cx: uart0::Context) { - let shared = cx.shared.shared.lock(|shared| { - *shared += 1; - *shared - }); - - hprintln!("UART0: shared = {}", shared); - } - - // `shared` can be accessed from this context - #[task(binds = UART1, shared = [shared])] - fn uart1(mut cx: uart1::Context) { - let shared = cx.shared.shared.lock(|shared| { - *shared += 1; - *shared - }); - - hprintln!("UART1: shared = {}", shared); - } -} diff --git a/rtic/examples/shared.rs b/rtic/examples/shared.rs deleted file mode 100644 index 79ebab8..0000000 --- a/rtic/examples/shared.rs +++ /dev/null @@ -1,51 +0,0 @@ -//! examples/late.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use heapless::spsc::{Consumer, Producer, Queue}; - use lm3s6965::Interrupt; - - #[shared] - struct Shared { - p: Producer<'static, u32, 5>, - c: Consumer<'static, u32, 5>, - } - - #[local] - struct Local {} - - #[init(local = [q: Queue = Queue::new()])] - fn init(cx: init::Context) -> (Shared, Local) { - let (p, c) = cx.local.q.split(); - - // Initialization of shared resources - (Shared { p, c }, Local {}) - } - - #[idle(shared = [c])] - fn idle(mut c: idle::Context) -> ! { - loop { - if let Some(byte) = c.shared.c.lock(|c| c.dequeue()) { - hprintln!("received message: {}", byte); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } else { - rtic::pend(Interrupt::UART0); - } - } - } - - #[task(binds = UART0, shared = [p])] - fn uart0(mut c: uart0::Context) { - c.shared.p.lock(|p| p.enqueue(42).unwrap()); - } -} diff --git a/rtic/examples/smallest.rs b/rtic/examples/smallest.rs deleted file mode 100644 index fee3f05..0000000 --- a/rtic/examples/smallest.rs +++ /dev/null @@ -1,27 +0,0 @@ -//! examples/smallest.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; // panic handler -use rtic::app; - -#[app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::debug; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - (Shared {}, Local {}) - } -} diff --git a/rtic/examples/spawn.rs b/rtic/examples/spawn.rs deleted file mode 100644 index 448bcda..0000000 --- a/rtic/examples/spawn.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! examples/spawn.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - hprintln!("init"); - foo::spawn().unwrap(); - - (Shared {}, Local {}) - } - - #[task] - async fn foo(_: foo::Context) { - hprintln!("foo"); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/rtic/examples/spawn_arguments.rs b/rtic/examples/spawn_arguments.rs deleted file mode 100644 index 61c4608..0000000 --- a/rtic/examples/spawn_arguments.rs +++ /dev/null @@ -1,34 +0,0 @@ -//! examples/spawn_arguments.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - foo::spawn(1, 1).unwrap(); - assert!(foo::spawn(1, 4).is_err()); // The capacity of `foo` is reached - - (Shared {}, Local {}) - } - - #[task] - async fn foo(_c: foo::Context, x: i32, y: u32) { - hprintln!("foo {}, {}", x, y); - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/rtic/examples/spawn_err.rs b/rtic/examples/spawn_err.rs deleted file mode 100644 index e5a9420..0000000 --- a/rtic/examples/spawn_err.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! examples/spawn_err.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - hprintln!("init"); - foo::spawn().unwrap(); - match foo::spawn() { - Ok(_) => {} - Err(()) => hprintln!("Cannot spawn a spawned (running) task!"), - } - - (Shared {}, Local {}) - } - - #[task] - async fn foo(_: foo::Context) { - hprintln!("foo"); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/rtic/examples/spawn_loop.rs b/rtic/examples/spawn_loop.rs deleted file mode 100644 index 13e386a..0000000 --- a/rtic/examples/spawn_loop.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! examples/spawn_loop.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - hprintln!("init"); - - (Shared {}, Local {}) - } - - #[idle] - fn idle(_: idle::Context) -> ! { - for _ in 0..3 { - foo::spawn().unwrap(); - hprintln!("idle"); - } - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - loop {} - } - - #[task(priority = 1)] - async fn foo(_: foo::Context) { - hprintln!("foo"); - } -} diff --git a/rtic/examples/static.rs b/rtic/examples/static.rs deleted file mode 100644 index fec73fc..0000000 --- a/rtic/examples/static.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! examples/static.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [UART0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - use heapless::spsc::{Consumer, Producer, Queue}; - - #[shared] - struct Shared {} - - #[local] - struct Local { - p: Producer<'static, u32, 5>, - c: Consumer<'static, u32, 5>, - } - - #[init(local = [q: Queue = Queue::new()])] - fn init(cx: init::Context) -> (Shared, Local) { - // q has 'static life-time so after the split and return of `init` - // it will continue to exist and be allocated - let (p, c) = cx.local.q.split(); - - foo::spawn().unwrap(); - - (Shared {}, Local { p, c }) - } - - #[idle(local = [c])] - fn idle(c: idle::Context) -> ! { - loop { - // Lock-free access to the same underlying queue! - if let Some(data) = c.local.c.dequeue() { - hprintln!("received message: {}", data); - - // Run foo until data - if data == 3 { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } else { - foo::spawn().unwrap(); - } - } - } - } - - #[task(local = [p, state: u32 = 0], priority = 1)] - async fn foo(c: foo::Context) { - *c.local.state += 1; - - // Lock-free access to the same underlying queue! - c.local.p.enqueue(*c.local.state).unwrap(); - } -} diff --git a/rtic/examples/t-binds.rs b/rtic/examples/t-binds.rs deleted file mode 100644 index 01c262c..0000000 --- a/rtic/examples/t-binds.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! [compile-pass] Check that `binds` works as advertised - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::debug; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - - (Shared {}, Local {}) - } - - // Cortex-M exception - #[task(binds = SVCall)] - fn foo(c: foo::Context) { - crate::foo_trampoline(c) - } - - // LM3S6965 interrupt - #[task(binds = UART0)] - fn bar(c: bar::Context) { - crate::bar_trampoline(c) - } -} - -#[allow(dead_code)] -fn foo_trampoline(_: app::foo::Context) {} - -#[allow(dead_code)] -fn bar_trampoline(_: app::bar::Context) {} diff --git a/rtic/examples/t-cfg-resources.rs b/rtic/examples/t-cfg-resources.rs deleted file mode 100644 index 2ddfae7..0000000 --- a/rtic/examples/t-cfg-resources.rs +++ /dev/null @@ -1,44 +0,0 @@ -//! [compile-pass] check that `#[cfg]` attributes applied on resources work - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::debug; - - #[shared] - struct Shared { - // A conditionally compiled resource behind feature_x - #[cfg(feature = "feature_x")] - x: u32, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - - ( - Shared { - #[cfg(feature = "feature_x")] - x: 0, - }, - Local {}, - ) - } - - #[idle] - fn idle(_cx: idle::Context) -> ! { - loop { - cortex_m::asm::nop(); - } - } -} diff --git a/rtic/examples/t-htask-main.rs b/rtic/examples/t-htask-main.rs deleted file mode 100644 index 61280f8..0000000 --- a/rtic/examples/t-htask-main.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! examples/t-task-main.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::debug; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - rtic::pend(lm3s6965::Interrupt::UART0); - - (Shared {}, Local {}) - } - - #[task(binds = UART0)] - fn taskmain(_: taskmain::Context) { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/rtic/examples/t-idle-main.rs b/rtic/examples/t-idle-main.rs deleted file mode 100644 index 88566a9..0000000 --- a/rtic/examples/t-idle-main.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! examples/t-idle-main.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965)] -mod app { - use cortex_m_semihosting::debug; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - (Shared {}, Local {}) - } - - #[idle] - fn taskmain(_: taskmain::Context) -> ! { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - loop { - cortex_m::asm::nop(); - } - } -} diff --git a/rtic/examples/t-late-not-send.rs b/rtic/examples/t-late-not-send.rs deleted file mode 100644 index be5cc66..0000000 --- a/rtic/examples/t-late-not-send.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! [compile-pass] shared resources don't need to be `Send` if they are owned by `idle` - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use core::marker::PhantomData; -use panic_semihosting as _; - -/// Not send -pub struct NotSend { - _0: PhantomData<*const ()>, -} - -#[rtic::app(device = lm3s6965)] -mod app { - use super::NotSend; - use core::marker::PhantomData; - use cortex_m_semihosting::debug; - - #[shared] - struct Shared { - x: NotSend, - y: Option, - } - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - ( - Shared { - x: NotSend { _0: PhantomData }, - y: None, - }, - Local {}, - ) - } - - #[idle(shared = [x, y])] - fn idle(_: idle::Context) -> ! { - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - loop { - cortex_m::asm::nop(); - } - } -} diff --git a/rtic/examples/task.rs b/rtic/examples/task.rs deleted file mode 100644 index b6b6bbd..0000000 --- a/rtic/examples/task.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! examples/task.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use panic_semihosting as _; - -#[rtic::app(device = lm3s6965, dispatchers = [SSI0, QEI0])] -mod app { - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared {} - - #[local] - struct Local {} - - #[init] - fn init(_: init::Context) -> (Shared, Local) { - foo::spawn().unwrap(); - - (Shared {}, Local {}) - } - - #[task] - async fn foo(_: foo::Context) { - hprintln!("foo - start"); - - // spawns `bar` onto the task scheduler - // `foo` and `bar` have the same priority so `bar` will not run until - // after `foo` terminates - bar::spawn().unwrap(); - - hprintln!("foo - middle"); - - // spawns `baz` onto the task scheduler - // `baz` has higher priority than `foo` so it immediately preempts `foo` - baz::spawn().unwrap(); - - hprintln!("foo - end"); - } - - #[task] - async fn bar(_: bar::Context) { - hprintln!("bar"); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } - - #[task(priority = 2)] - async fn baz(_: baz::Context) { - hprintln!("baz"); - } -} diff --git a/rtic/examples/zero-prio-task.rs b/rtic/examples/zero-prio-task.rs deleted file mode 100644 index 8cfd705..0000000 --- a/rtic/examples/zero-prio-task.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! examples/zero-prio-task.rs - -#![no_main] -#![no_std] -#![deny(warnings)] -#![deny(unsafe_code)] -#![deny(missing_docs)] - -use core::marker::PhantomData; -use panic_semihosting as _; - -/// Does not impl send -pub struct NotSend { - _0: PhantomData<*const ()>, -} - -#[rtic::app(device = lm3s6965, peripherals = true)] -mod app { - use super::NotSend; - use core::marker::PhantomData; - use cortex_m_semihosting::{debug, hprintln}; - - #[shared] - struct Shared { - x: NotSend, - } - - #[local] - struct Local { - y: NotSend, - } - - #[init] - fn init(_cx: init::Context) -> (Shared, Local) { - hprintln!("init"); - - async_task::spawn().unwrap(); - async_task2::spawn().unwrap(); - - ( - Shared { - x: NotSend { _0: PhantomData }, - }, - Local { - y: NotSend { _0: PhantomData }, - }, - ) - } - - #[task(priority = 0, shared = [x], local = [y])] - async fn async_task(_: async_task::Context) { - hprintln!("hello from async"); - } - - #[task(priority = 0, shared = [x])] - async fn async_task2(_: async_task2::Context) { - hprintln!("hello from async2"); - - debug::exit(debug::EXIT_SUCCESS); // Exit QEMU simulator - } -} diff --git a/rtic/src/export.rs b/rtic/src/export.rs index 0fc995e..4fd8e78 100644 --- a/rtic/src/export.rs +++ b/rtic/src/export.rs @@ -12,41 +12,37 @@ pub use cortex_common::*; mod cortex_common; // Cortex-M target with basepri support -#[cfg(any(feature = "cortex-m-basepri", feature = "rtic-uitestv7"))] +#[cfg(feature = "cortex-m-basepri")] mod cortex_basepri; -#[cfg(any(feature = "cortex-m-basepri", feature = "rtic-uitestv7"))] +#[cfg(feature = "cortex-m-basepri")] pub use cortex_basepri::*; // Cortex-M target with source mask support -#[cfg(any(feature = "cortex-m-source-masking", feature = "rtic-uitestv6"))] +#[cfg(feature = "cortex-m-source-masking")] mod cortex_source_mask; -#[cfg(any(feature = "cortex-m-source-masking", feature = "rtic-uitestv6"))] +#[cfg(feature = "cortex-m-source-masking")] pub use cortex_source_mask::*; -// RISC-V target (any) #[cfg(feature = "riscv")] -pub use riscv_common::*; +pub mod riscv_common; #[cfg(feature = "riscv")] -mod riscv_common; +pub use riscv_common::*; #[cfg(feature = "riscv-esp32c3")] mod riscv_esp32c3; #[cfg(feature = "riscv-esp32c3")] pub use riscv_esp32c3::*; +#[cfg(feature = "riscv-slic")] +mod slic; +#[cfg(feature = "riscv-slic")] +pub use slic::*; + #[inline(always)] -pub fn assert_send() -where - T: Send, -{ -} +pub fn assert_send() {} #[inline(always)] -pub fn assert_sync() -where - T: Sync, -{ -} +pub fn assert_sync() {} diff --git a/rtic/src/export/riscv_common.rs b/rtic/src/export/riscv_common.rs index 6189335..d3028b4 100644 --- a/rtic/src/export/riscv_common.rs +++ b/rtic/src/export/riscv_common.rs @@ -1,10 +1,9 @@ /// GENERIC RE-EXPORTS: needed for all RTIC backends -pub use riscv::interrupt; /// Read the stack pointer. #[inline(always)] pub fn read_sp() -> u32 { let r; - unsafe { asm!("mv {}, sp", out(reg) r, options(nomem, nostack, preserves_flags)) }; + unsafe { core::arch::asm!("mv {}, sp", out(reg) r, options(nomem, nostack, preserves_flags)) }; r } diff --git a/rtic/src/export/riscv_esp32c3.rs b/rtic/src/export/riscv_esp32c3.rs index de09113..5780d40 100644 --- a/rtic/src/export/riscv_esp32c3.rs +++ b/rtic/src/export/riscv_esp32c3.rs @@ -1,5 +1,6 @@ use esp32c3::INTERRUPT_CORE0; //priority threshold control pub use esp32c3::{Interrupt, Peripherals}; +pub use riscv::interrupt; pub use riscv::register::mcause; //low level interrupt enable/disable #[cfg(all(feature = "riscv-esp32c3", not(feature = "riscv-esp32c3-backend")))] diff --git a/rtic/src/export/slic.rs b/rtic/src/export/slic.rs new file mode 100644 index 0000000..f0c17a3 --- /dev/null +++ b/rtic/src/export/slic.rs @@ -0,0 +1,19 @@ +pub use riscv_slic::{lock, pend, run, InterruptNumber}; + +#[cfg(all(feature = "riscv-slic", not(feature = "riscv-clint-backend")))] +compile_error!("Building for the riscv-slic, but 'riscv-clint-backend' not selected"); + +/// USE CASE RE-EXPORTS: needed for SLIC-only +pub use riscv_slic::{self, clear_interrupts, codegen, set_interrupts, set_priority}; + +pub mod interrupt { + pub fn disable() { + riscv_slic::disable(); + riscv_slic::clear_interrupts(); + } + + pub unsafe fn enable() { + riscv_slic::set_interrupts(); + riscv_slic::enable(); + } +} diff --git a/rtic/src/lib.rs b/rtic/src/lib.rs index bbdd5e2..2932c22 100644 --- a/rtic/src/lib.rs +++ b/rtic/src/lib.rs @@ -45,7 +45,6 @@ pub mod mutex { #[doc(hidden)] pub mod export; -#[cfg(feature = "cortex-m")] pub use export::pend; use core::cell::UnsafeCell; diff --git a/xtask/src/argument_parsing.rs b/xtask/src/argument_parsing.rs index 3893c61..a3a404f 100644 --- a/xtask/src/argument_parsing.rs +++ b/xtask/src/argument_parsing.rs @@ -1,4 +1,7 @@ -use crate::{cargo_command::CargoCommand, Target, ARMV6M, ARMV7M, ARMV8MBASE, ARMV8MMAIN}; +use crate::{ + cargo_command::CargoCommand, Target, ARMV6M, ARMV7M, ARMV8MBASE, ARMV8MMAIN, RISCV32IMAC, + RISCV32IMC, +}; use clap::{Args, Parser, Subcommand}; use core::fmt; @@ -84,7 +87,7 @@ impl Package { }; features - .into_iter() + .iter() .map(ToString::to_string) .map(Some) .chain(std::iter::once(None)) @@ -101,12 +104,7 @@ impl TestMetadata { pub fn match_package(package: Package, backend: Backends) -> CargoCommand<'static> { match package { Package::Rtic => { - let features = format!( - "{},{}", - backend.to_rtic_feature(), - backend.to_rtic_uitest_feature() - ); - let features = Some(backend.to_target().and_features(&features)); + let features = Some(backend.to_target().and_features(backend.to_rtic_feature())); CargoCommand::Test { package: Some(package.name()), features, @@ -155,6 +153,9 @@ pub enum Backends { Thumbv7, Thumbv8Base, Thumbv8Main, + RiscvEsp32C3, + Riscv32ImcClint, // not working yet (issues with portable-atomic features...) + Riscv32ImacClint, } impl Backends { @@ -165,6 +166,8 @@ impl Backends { Backends::Thumbv7 => ARMV7M, Backends::Thumbv8Base => ARMV8MBASE, Backends::Thumbv8Main => ARMV8MMAIN, + Backends::Riscv32ImcClint => RISCV32IMC, + Backends::RiscvEsp32C3 | Backends::Riscv32ImacClint => RISCV32IMAC, } } @@ -175,6 +178,8 @@ impl Backends { Backends::Thumbv7 => "thumbv7-backend", Backends::Thumbv8Base => "thumbv8base-backend", Backends::Thumbv8Main => "thumbv8main-backend", + Backends::RiscvEsp32C3 => "riscv-esp32c3-backend", + Backends::Riscv32ImcClint | Backends::Riscv32ImacClint => "riscv-clint-backend", } } #[allow(clippy::wrong_self_convention)] @@ -182,13 +187,8 @@ impl Backends { match self { Backends::Thumbv6 | Backends::Thumbv8Base => "cortex-m-source-masking", Backends::Thumbv7 | Backends::Thumbv8Main => "cortex-m-basepri", - } - } - #[allow(clippy::wrong_self_convention)] - pub fn to_rtic_uitest_feature(&self) -> &'static str { - match self { - Backends::Thumbv6 | Backends::Thumbv8Base => "rtic-uitestv6", - Backends::Thumbv7 | Backends::Thumbv8Main => "rtic-uitestv7", + Backends::RiscvEsp32C3 => "riscv-esp32c3", + Backends::Riscv32ImcClint | Backends::Riscv32ImacClint => "riscv-clint", } } } @@ -200,14 +200,127 @@ pub enum BuildOrCheck { Build, } +#[derive(clap::ValueEnum, Copy, Clone, Default, Debug)] +pub enum Platforms { + Hifive1, + #[default] + Lm3s6965, + Nrf52840, + Rp2040, + Stm32f3, + Stm32f411, + Teensy4, +} + +impl Platforms { + pub fn name(&self) -> String { + let name = match self { + Platforms::Hifive1 => "hifive1", + Platforms::Lm3s6965 => "lm3s6965", + Platforms::Nrf52840 => "nrf52840", + Platforms::Rp2040 => "rp2040", + Platforms::Stm32f3 => "stm32f3", + Platforms::Stm32f411 => "stm32f411", + Platforms::Teensy4 => "teensy4", + }; + name.to_string() + } + + /// Rust flags needed for the platform when building + pub fn rust_flags(&self) -> Vec { + let c = "-C".to_string(); + match self { + Platforms::Hifive1 => vec![c, "link-arg=-Thifive1-link.x".to_string()], + Platforms::Lm3s6965 => vec![c, "link-arg=-Tlink.x".to_string()], + Platforms::Nrf52840 => vec![ + c.clone(), + "linker=flip-link".to_string(), + c.clone(), + "link-arg=-Tlink.x".to_string(), + c.clone(), + "link-arg=-Tdefmt.x".to_string(), + c, + "link-arg=--nmagic".to_string(), + ], + Platforms::Rp2040 => vec![ + c.clone(), + "link-arg=--nmagic".to_string(), + c, + "link-arg=-Tlink.x".to_string(), + ], + Platforms::Stm32f3 => vec![ + c.clone(), + "link-arg=--nmagic".to_string(), + c, + "link-arg=-Tlink.x".to_string(), + ], + Platforms::Stm32f411 => vec![ + c.clone(), + "link-arg=-Tlink.x".to_string(), + c, + "link-arg=-Tdefmt.x".to_string(), + ], + Platforms::Teensy4 => vec![c, "link-arg=-Tt4link.x".to_string()], + } + } + + /// Get the default backend for the platform + pub fn default_backend(&self) -> Backends { + match self { + Platforms::Hifive1 => Backends::Riscv32ImcClint, + Platforms::Lm3s6965 => Backends::Thumbv7, + Platforms::Nrf52840 => unimplemented!(), + Platforms::Rp2040 => unimplemented!(), + Platforms::Stm32f3 => unimplemented!(), + Platforms::Stm32f411 => unimplemented!(), + Platforms::Teensy4 => unimplemented!(), + } + } + + /// Get the features needed given the selected platform and backend. + /// If the backend is not supported for the platform, return Err. + /// If the backend is supported, but no special features are needed, return Ok(None). + pub fn features(&self, backend: &Backends) -> Result, ()> { + match self { + Platforms::Hifive1 => match backend.to_target() { + RISCV32IMC | RISCV32IMAC => Ok(None), + _ => Err(()), + }, + Platforms::Lm3s6965 => match backend.to_target() { + ARMV6M => Ok(Some("thumbv6-backend")), + ARMV7M => Ok(Some("thumbv7-backend")), + ARMV8MBASE => Ok(Some("thumbv8base-backend")), + ARMV8MMAIN => Ok(Some("thumbv8main-backend")), + _ => Err(()), + }, + Platforms::Nrf52840 => unimplemented!(), + Platforms::Rp2040 => unimplemented!(), + Platforms::Stm32f3 => unimplemented!(), + Platforms::Stm32f411 => unimplemented!(), + Platforms::Teensy4 => unimplemented!(), + } + } +} + #[derive(Parser, Clone)] pub struct Globals { /// Error out on warnings #[arg(short = 'D', long)] pub deny_warnings: bool, + /// For which platform to build. + /// + /// If omitted, the default platform (i.e., lm3s6965) is used. + /// + /// Example: `cargo xtask --platform lm3s6965` + #[arg(value_enum, short, default_value = "lm3s6965", long, global = true)] + pub platform: Option, + /// For which backend to build. - #[arg(value_enum, short, default_value = "thumbv7", long, global = true)] + /// + /// If omitted, the default backend for the selected platform is used + /// (check [`Platforms::default_backend`]). + #[arg(value_enum, short, long, global = true)] pub backend: Option, /// List of comma separated examples to include, all others are excluded @@ -316,55 +429,6 @@ pub enum Commands { /// Build books with mdbook Book(Arg), - - /// Check one or more usage examples. - /// - /// Usage examples are located in ./examples - UsageExampleCheck(UsageExamplesOpt), - - /// Build one or more usage examples. - /// - /// Usage examples are located in ./examples - #[clap(alias = "./examples")] - UsageExampleBuild(UsageExamplesOpt), -} - -#[derive(Args, Clone, Debug)] -pub struct UsageExamplesOpt { - /// The usage examples to build. All usage examples are selected if this argument is not provided. - /// - /// Example: `rp2040_local_i2c_init,stm32f3_blinky`. - examples: Option, -} - -impl UsageExamplesOpt { - pub fn examples(&self) -> anyhow::Result> { - let usage_examples: Vec<_> = std::fs::read_dir("./examples")? - .filter_map(Result::ok) - .filter(|p| p.metadata().ok().map(|p| p.is_dir()).unwrap_or(false)) - .filter_map(|p| p.file_name().to_str().map(ToString::to_string)) - .collect(); - - let selected_examples: Option> = self - .examples - .clone() - .map(|s| s.split(",").map(ToString::to_string).collect()); - - if let Some(selected_examples) = selected_examples { - if let Some(unfound_example) = selected_examples - .iter() - .find(|e| !usage_examples.contains(e)) - { - Err(anyhow::anyhow!( - "Usage example {unfound_example} does not exist" - )) - } else { - Ok(selected_examples) - } - } else { - Ok(usage_examples) - } - } } #[derive(Args, Debug, Clone)] diff --git a/xtask/src/cargo_command.rs b/xtask/src/cargo_command.rs index c5387c2..78e81b1 100644 --- a/xtask/src/cargo_command.rs +++ b/xtask/src/cargo_command.rs @@ -1,4 +1,4 @@ -use crate::{ExtraArguments, Target}; +use crate::{ExtraArguments, Platforms, Target}; use core::fmt; use std::path::PathBuf; @@ -15,6 +15,7 @@ pub enum CargoCommand<'a> { #[allow(dead_code)] Run { cargoarg: &'a Option<&'a str>, + platform: Platforms, // to tell which platform. If None, it assumes lm3s6965 example: &'a str, target: Option>, features: Option, @@ -23,6 +24,7 @@ pub enum CargoCommand<'a> { }, Qemu { cargoarg: &'a Option<&'a str>, + platform: Platforms, // to tell which platform. If None, it assumes lm3s6965 example: &'a str, target: Option>, features: Option, @@ -32,6 +34,7 @@ pub enum CargoCommand<'a> { }, ExampleBuild { cargoarg: &'a Option<&'a str>, + platform: Platforms, // to tell which platform. If None, it assumes lm3s6965 example: &'a str, target: Option>, features: Option, @@ -41,10 +44,12 @@ pub enum CargoCommand<'a> { }, ExampleCheck { cargoarg: &'a Option<&'a str>, + platform: Platforms, // to tell which platform. If None, it assumes lm3s6965 example: &'a str, target: Option>, features: Option, mode: BuildMode, + dir: Option, deny_warnings: bool, }, Build { @@ -94,6 +99,7 @@ pub enum CargoCommand<'a> { }, ExampleSize { cargoarg: &'a Option<&'a str>, + platform: Platforms, // to tell which platform. If None, it assumes lm3s6965 example: &'a str, target: Option>, features: Option, @@ -137,6 +143,7 @@ impl core::fmt::Display for CargoCommand<'_> { features: &Option, cargoarg: &&Option<&str>, path: Option<&PathBuf>, + // no need to add platform, as it is implicit in the path ) -> String { let feat = feat(features); let carg = carg(cargoarg); @@ -179,6 +186,7 @@ impl core::fmt::Display for CargoCommand<'_> { match self { CargoCommand::Run { cargoarg, + platform: _, example, target, features, @@ -193,6 +201,7 @@ impl core::fmt::Display for CargoCommand<'_> { } CargoCommand::Qemu { cargoarg, + platform: _, example, target, features, @@ -206,6 +215,7 @@ impl core::fmt::Display for CargoCommand<'_> { } CargoCommand::ExampleBuild { cargoarg, + platform: _, example, target, features, @@ -219,16 +229,18 @@ impl core::fmt::Display for CargoCommand<'_> { } CargoCommand::ExampleCheck { cargoarg, + platform: _, example, target, features, mode, + dir, deny_warnings, - } => write!( - f, - "Check example {example} {}", - details(*deny_warnings, target, Some(mode), features, cargoarg, None) - ), + } => { + let warns = *deny_warnings; + let details = details(warns, target, Some(mode), features, cargoarg, dir.as_ref()); + write!(f, "Check example {example} {details}",) + } CargoCommand::Build { cargoarg, package, @@ -329,17 +341,14 @@ impl core::fmt::Display for CargoCommand<'_> { .clone() .map(|t| format!("test {t}")) .unwrap_or("all tests".into()); - let deny_warnings = if *deny_warnings { - format!("deny warnings, ") - } else { - format!("") - }; - let feat = feat(features); - write!(f, "Run {test} in {p} ({deny_warnings}features: {feat})") + + let details = details(*deny_warnings, &None, None, features, &&None, None); + write!(f, "Run {test} in {p} {details}") } CargoCommand::Book { arguments: _ } => write!(f, "Build the book"), CargoCommand::ExampleSize { cargoarg, + platform: _, example, target, features, @@ -475,6 +484,7 @@ impl<'a> CargoCommand<'a> { // For future embedded-ci, for now the same as Qemu CargoCommand::Run { cargoarg, + platform: _, example, features, mode, @@ -491,6 +501,7 @@ impl<'a> CargoCommand<'a> { ), CargoCommand::Qemu { cargoarg, + platform: _, example, features, mode, @@ -606,6 +617,7 @@ impl<'a> CargoCommand<'a> { } CargoCommand::ExampleBuild { cargoarg, + platform: _, example, features, mode, @@ -624,9 +636,11 @@ impl<'a> CargoCommand<'a> { ), CargoCommand::ExampleCheck { cargoarg, + platform: _, example, features, mode, + dir: _, // Target is added by build_args target: _, // deny_warnings is exposed through `extra_env` @@ -640,6 +654,7 @@ impl<'a> CargoCommand<'a> { ), CargoCommand::ExampleSize { cargoarg, + platform: _, example, features, mode, @@ -664,6 +679,7 @@ impl<'a> CargoCommand<'a> { pub fn chdir(&self) -> Option<&PathBuf> { match self { CargoCommand::Qemu { dir, .. } + | CargoCommand::ExampleCheck { dir, .. } | CargoCommand::ExampleBuild { dir, .. } | CargoCommand::ExampleSize { dir, .. } | CargoCommand::Build { dir, .. } @@ -687,20 +703,35 @@ impl<'a> CargoCommand<'a> { } } - pub fn extra_env(&self) -> Option<(&str, &str)> { + pub fn extra_env(&self) -> Option<(&str, String)> { match self { // Clippy is a special case: it sets deny warnings // through an argument to rustc. CargoCommand::Clippy { .. } => None, - CargoCommand::Doc { .. } => Some(("RUSTDOCFLAGS", "-D warnings")), + CargoCommand::Doc { .. } => Some(("RUSTDOCFLAGS", "-D warnings".to_string())), - CargoCommand::Qemu { deny_warnings, .. } - | CargoCommand::ExampleBuild { deny_warnings, .. } - | CargoCommand::ExampleSize { deny_warnings, .. } => { + CargoCommand::Qemu { + platform, + deny_warnings, + .. + } + | CargoCommand::ExampleBuild { + platform, + deny_warnings, + .. + } + | CargoCommand::ExampleSize { + platform, + deny_warnings, + .. + } => { if *deny_warnings { + let rust_flags = platform.rust_flags().join(" "); + let rust_flags = format!("-D warnings {}", rust_flags); // NOTE: this also needs the link-arg because .cargo/config.toml // is ignored if you set the RUSTFLAGS env variable. - Some(("RUSTFLAGS", "-D warnings -C link-arg=-Tlink.x")) + Some(("RUSTFLAGS", rust_flags)) + // TODO make this configurable } else { None } @@ -711,7 +742,7 @@ impl<'a> CargoCommand<'a> { | CargoCommand::Build { deny_warnings, .. } | CargoCommand::Test { deny_warnings, .. } => { if *deny_warnings { - Some(("RUSTFLAGS", "-D warnings")) + Some(("RUSTFLAGS", "-D warnings".to_string())) } else { None } diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 90ba13f..0c56b42 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -11,12 +11,12 @@ use std::{path::Path, str}; use log::{error, info, log_enabled, trace, Level}; use crate::{ - argument_parsing::{Backends, BuildOrCheck, Cli, Commands}, + argument_parsing::{BuildOrCheck, Cli, Commands, Platforms}, build::init_build_dir, run::*, }; -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Eq, PartialEq)] pub struct Target<'a> { triple: &'a str, has_std: bool, @@ -54,6 +54,8 @@ const ARMV6M: Target = Target::new("thumbv6m-none-eabi", false); const ARMV7M: Target = Target::new("thumbv7m-none-eabi", false); const ARMV8MBASE: Target = Target::new("thumbv8m.base-none-eabi", false); const ARMV8MMAIN: Target = Target::new("thumbv8m.main-none-eabi", false); +const RISCV32IMC: Target = Target::new("riscv32imc-unknown-none-elf", false); +const RISCV32IMAC: Target = Target::new("riscv32imac-unknown-none-elf", false); fn main() -> anyhow::Result<()> { // if there's an `xtask` folder, we're *probably* at the root of this repo (we can't just @@ -65,13 +67,6 @@ fn main() -> anyhow::Result<()> { )); } - let examples: Vec<_> = std::fs::read_dir("./rtic/examples")? - .filter_map(|p| p.ok()) - .map(|p| p.path()) - .filter(|p| p.display().to_string().ends_with(".rs")) - .map(|path| path.file_stem().unwrap().to_str().unwrap().to_string()) - .collect(); - let cli = Cli::parse(); let globals = &cli.globals; @@ -94,12 +89,35 @@ fn main() -> anyhow::Result<()> { ); log::debug!("Partial features: {}", globals.partial); + let platform = if let Some(platform) = globals.platform { + platform + } else { + Platforms::default() + }; + let backend = if let Some(backend) = globals.backend { backend } else { - Backends::default() + platform.default_backend() }; + // Check if the platform supports the backend + if platform.features(&backend).is_err() { + return Err(anyhow::anyhow!( + "platform {:?} does not support backend {:?}", + platform, + backend + )); + } + + let examples_path = format!("./examples/{}/examples", platform.name()); + let examples: Vec<_> = std::fs::read_dir(examples_path)? + .filter_map(|p| p.ok()) + .map(|p| p.path()) + .filter(|p| p.display().to_string().ends_with(".rs")) + .map(|path| path.file_stem().unwrap().to_str().unwrap().to_string()) + .collect(); + let example = globals.example.clone(); let exampleexclude = globals.exampleexclude.clone(); @@ -163,42 +181,45 @@ fn main() -> anyhow::Result<()> { Commands::Format(args) => cargo_format(globals, &cargologlevel, &args.package, args.check), Commands::Clippy(args) => { info!("Running clippy on backend: {backend:?}"); - cargo_clippy(globals, &cargologlevel, &args, backend) + cargo_clippy(globals, &cargologlevel, args, backend) } Commands::Check(args) => { info!("Checking on backend: {backend:?}"); - cargo(globals, BuildOrCheck::Check, &cargologlevel, &args, backend) + cargo(globals, BuildOrCheck::Check, &cargologlevel, args, backend) } Commands::Build(args) => { info!("Building for backend: {backend:?}"); - cargo(globals, BuildOrCheck::Build, &cargologlevel, &args, backend) + cargo(globals, BuildOrCheck::Build, &cargologlevel, args, backend) } Commands::ExampleCheck => { - info!("Checking on backend: {backend:?}"); + info!("Checking on platform: {platform:?}, backend: {backend:?}"); cargo_example( globals, BuildOrCheck::Check, &cargologlevel, + platform, backend, &examples_to_run, ) } Commands::ExampleBuild => { - info!("Building for backend: {backend:?}"); + info!("Building for platform: {platform:?}, backend: {backend:?}"); cargo_example( globals, BuildOrCheck::Build, &cargologlevel, + platform, backend, &examples_to_run, ) } Commands::Size(args) => { // x86_64 target not valid - info!("Measuring for backend: {backend:?}"); + info!("Measuring for platform: {platform:?}, backend: {backend:?}"); build_and_check_size( globals, &cargologlevel, + platform, backend, &examples_to_run, &args.arguments, @@ -206,10 +227,11 @@ fn main() -> anyhow::Result<()> { } Commands::Qemu(args) | Commands::Run(args) => { // x86_64 target not valid - info!("Testing for backend: {backend:?}"); + info!("Testing for platform: {platform:?}, backend: {backend:?}"); qemu_run_examples( globals, &cargologlevel, + platform, backend, &examples_to_run, args.overwrite_expected, @@ -221,20 +243,12 @@ fn main() -> anyhow::Result<()> { } Commands::Test(args) => { info!("Running cargo test on backend: {backend:?}"); - cargo_test(globals, &args, backend) + cargo_test(globals, args, backend) } Commands::Book(args) => { info!("Running mdbook"); cargo_book(globals, &args.arguments) } - Commands::UsageExampleCheck(examples) => { - info!("Checking usage examples"); - cargo_usage_example(globals, BuildOrCheck::Check, examples.examples()?) - } - Commands::UsageExampleBuild(examples) => { - info!("Building usage examples"); - cargo_usage_example(globals, BuildOrCheck::Build, examples.examples()?) - } }; handle_results(globals, final_run_results).map_err(|_| anyhow::anyhow!("Commands failed")) diff --git a/xtask/src/run.rs b/xtask/src/run.rs index 6057551..ff81e6a 100644 --- a/xtask/src/run.rs +++ b/xtask/src/run.rs @@ -15,7 +15,9 @@ mod iter; use iter::{into_iter, CoalescingRunner}; use crate::{ - argument_parsing::{Backends, BuildOrCheck, ExtraArguments, Globals, PackageOpt, TestMetadata}, + argument_parsing::{ + Backends, BuildOrCheck, ExtraArguments, Globals, PackageOpt, Platforms, TestMetadata, + }, cargo_command::{BuildMode, CargoCommand}, }; @@ -62,7 +64,12 @@ fn command_parser( }; match *command { - CargoCommand::Qemu { example, .. } | CargoCommand::Run { example, .. } => { + CargoCommand::Qemu { + platform, example, .. + } + | CargoCommand::Run { + platform, example, .. + } => { /// Check if `run` was successful. /// returns Ok in case the run went as expected, /// Err otherwise @@ -99,8 +106,9 @@ fn command_parser( res } + let platform_name = platform.name(); let run_file = format!("{example}.run"); - let expected_output_file = ["rtic", "ci", "expected", &run_file] + let expected_output_file = ["ci", "expected", &platform_name, &run_file] .iter() .collect::() .into_os_string() @@ -191,72 +199,41 @@ pub fn cargo<'c>( runner.run_and_coalesce() } -/// Cargo command to build a usage example. -/// -/// The usage examples are in examples/ -pub fn cargo_usage_example( - globals: &Globals, - operation: BuildOrCheck, - usage_examples: Vec, -) -> Vec> { - into_iter(&usage_examples) - .map(|example| { - let path = format!("examples/{example}"); - - let command = match operation { - BuildOrCheck::Check => CargoCommand::Check { - cargoarg: &None, - mode: BuildMode::Release, - dir: Some(path.into()), - package: None, - target: None, - features: None, - deny_warnings: globals.deny_warnings, - }, - BuildOrCheck::Build => CargoCommand::Build { - cargoarg: &None, - package: None, - target: None, - features: None, - mode: BuildMode::Release, - dir: Some(path.into()), - deny_warnings: globals.deny_warnings, - }, - }; - (globals, command, false) - }) - .run_and_coalesce() -} - /// Cargo command to either build or check all examples /// -/// The examples are in rtic/examples +/// The examples are in examples//examples pub fn cargo_example<'c>( globals: &Globals, operation: BuildOrCheck, cargoarg: &'c Option<&'c str>, + platform: Platforms, backend: Backends, examples: &'c [String], ) -> Vec> { let runner = into_iter(examples).map(|example| { + let path = format!("examples/{}", platform.name()); + let dir = Some(PathBuf::from(path)); let features = Some(backend.to_target().and_features(backend.to_rtic_feature())); let command = match operation { BuildOrCheck::Check => CargoCommand::ExampleCheck { cargoarg, + platform, example, target: Some(backend.to_target()), features, mode: BuildMode::Release, + dir, deny_warnings: globals.deny_warnings, }, BuildOrCheck::Build => CargoCommand::ExampleBuild { cargoarg, + platform, example, target: Some(backend.to_target()), features, mode: BuildMode::Release, - dir: Some(PathBuf::from("./rtic")), + dir, deny_warnings: globals.deny_warnings, }, }; @@ -368,9 +345,12 @@ pub fn cargo_book<'c>( /// Run examples /// /// Supports updating the expected output via the overwrite argument +/// +/// The examples are in examples//examples pub fn qemu_run_examples<'c>( globals: &Globals, cargoarg: &'c Option<&'c str>, + platform: Platforms, backend: Backends, examples: &'c [String], overwrite: bool, @@ -380,11 +360,13 @@ pub fn qemu_run_examples<'c>( into_iter(examples) .flat_map(|example| { + let path = format!("examples/{}", platform.name()); + let dir = Some(PathBuf::from(path)); let target = target.into(); - let dir = Some(PathBuf::from("./rtic")); let cmd_build = CargoCommand::ExampleBuild { cargoarg: &None, + platform, example, target, features: features.clone(), @@ -395,6 +377,7 @@ pub fn qemu_run_examples<'c>( let cmd_qemu = CargoCommand::Qemu { cargoarg, + platform, example, target, features: features.clone(), @@ -413,6 +396,7 @@ pub fn qemu_run_examples<'c>( pub fn build_and_check_size<'c>( globals: &Globals, cargoarg: &'c Option<&'c str>, + platform: Platforms, backend: Backends, examples: &'c [String], arguments: &'c Option, @@ -422,27 +406,31 @@ pub fn build_and_check_size<'c>( let runner = into_iter(examples) .flat_map(|example| { + let path = format!("examples/{}", platform.name()); + let dir = Some(PathBuf::from(path)); let target = target.into(); // Make sure the requested example(s) are built let cmd_build = CargoCommand::ExampleBuild { cargoarg: &Some("--quiet"), + platform, example, target, features: features.clone(), mode: BuildMode::Release, - dir: Some(PathBuf::from("./rtic")), + dir: dir.clone(), deny_warnings: globals.deny_warnings, }; let cmd_size = CargoCommand::ExampleSize { cargoarg, + platform, example, target, features: features.clone(), mode: BuildMode::Release, arguments: arguments.clone(), - dir: Some(PathBuf::from("./rtic")), + dir, deny_warnings: globals.deny_warnings, }; -- cgit v1.2.3