Skip to content

Commit 7b6d052

Browse files
committed
Merge branch '✨-armv6m' into 🦆
2 parents 4e4ed96 + ee645a5 commit 7b6d052

File tree

11 files changed

+511
-53
lines changed

11 files changed

+511
-53
lines changed

.github/workflows/ci.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,16 @@ jobs:
9595
sudo apt-get install libusb-1.0-0-dev qemu-system-arm
9696
9797
- name: Install Additional Target of the Rust Toolchain
98-
run: rustup target add thumbv7m-none-eabi
98+
run: rustup target add thumbv6m-none-eabi thumbv7m-none-eabi
9999

100-
- name: Test (MPS2+ AN385)
100+
- name: Test (MPS2+ AN385, Armv7-M)
101101
uses: actions-rs/cargo@v1
102102
with:
103103
command: run
104104
args: -p constance_port_arm_m_test_runner -- -t qemu_mps2_an385 -l debug
105+
106+
- name: Test (MPS2+ AN385, Armv6-M)
107+
uses: actions-rs/cargo@v1
108+
with:
109+
command: run
110+
args: -p constance_port_arm_m_test_runner -- -t qemu_mps2_an385_v6m -l debug

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Constance is a proof-of-concept of a static RTOS that utilizes Rust's compile-ti
2323
| :--------------- | :-------------- | :----------------- |
2424
| ☑︎ Tasks |`Mutex` | ☑︎ `std` (Hosted) |
2525
| ☑︎ Hunks |`RwLock` | ☑︎ Armv7-M (no FPU) |
26-
| ☑︎ Wait Objects |`Once` | |
26+
| ☑︎ Wait Objects |`Once` | ☑︎ Armv6-M |
2727
| ☑︎ Timeouts | ☐ Logger | |
2828
| ☐ Semaphores | ☐ C API | |
2929
| ☑︎ Event Groups | | |
@@ -132,5 +132,6 @@ In this case, you need to run `rustup target add thumbv7m-none-eabi`.
132132
### How to Run Tests
133133

134134
- Hosted platform and target-independent tests: `cargo test --all`
135-
- The Arm-M port and NUCLEO-F401RE: `cargo run -p constance_port_arm_m_test_runner -- -t nucleo_f401re`
136-
- The Arm-M port and Arm MPS2+ AN385 (QEMU emulation): `cargo run -p constance_port_arm_m_test_runner -- -t qemu_mps2_an385`
135+
- The Armv7-M port and NUCLEO-F401RE: `cargo run -p constance_port_arm_m_test_runner -- -t nucleo_f401re`
136+
- The Armv7-M port and Arm MPS2+ AN385 (QEMU emulation): `cargo run -p constance_port_arm_m_test_runner -- -t qemu_mps2_an385`
137+
- The Armv6-M port and Arm MPS2+ AN385 (QEMU emulation): `cargo run -p constance_port_arm_m_test_runner -- -t qemu_mps2_an385_v6m`

src/constance_port_arm_m/build.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use std::env;
2+
3+
fn main() {
4+
let target = env::var("TARGET").unwrap();
5+
6+
if target.starts_with("thumbv6m-") {
7+
println!("cargo:rustc-cfg=cortex_m");
8+
println!("cargo:rustc-cfg=armv6m");
9+
} else if target.starts_with("thumbv7m-") || target.starts_with("thumbv7em-") {
10+
println!("cargo:rustc-cfg=cortex_m");
11+
println!("cargo:rustc-cfg=armv7m");
12+
} else if target.starts_with("thumbv8m.base") {
13+
println!("cargo:rustc-cfg=cortex_m");
14+
println!("cargo:rustc-cfg=armv8m");
15+
println!("cargo:rustc-cfg=armv8m_base");
16+
} else if target.starts_with("thumbv8m.main") {
17+
println!("cargo:rustc-cfg=cortex_m");
18+
println!("cargo:rustc-cfg=armv8m");
19+
println!("cargo:rustc-cfg=armv8m_main");
20+
}
21+
22+
if target.ends_with("-eabihf") {
23+
println!("cargo:rustc-cfg=has_fpu");
24+
}
25+
}

src/constance_port_arm_m/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#![feature(external_doc)]
22
#![feature(const_fn)]
33
#![feature(llvm_asm)]
4+
#![feature(decl_macro)]
45
#![feature(const_panic)]
56
#![feature(const_generics)]
67
#![feature(slice_ptr_len)]
@@ -63,7 +64,8 @@ pub trait ThreadingOptions {
6364
///
6465
/// [`MANAGED_INTERRUPT_PRIORITY_RANGE`]: constance::kernel::PortInterrupts::MANAGED_INTERRUPT_PRIORITY_RANGE
6566
///
66-
/// Must be `0` on an Armv6-M target because it doesn't support `BASEPRI`.
67+
/// Must be `0` on Armv6-M and Armv8-M Baseline because they don't support
68+
/// `BASEPRI`.
6769
const CPU_LOCK_PRIORITY_MASK: u8 = 0;
6870

6971
/// Enables the use of the `wfi` instruction in the idle task to save power.
@@ -253,6 +255,8 @@ macro_rules! use_port {
253255
}
254256
}
255257

258+
const _: () = $crate::threading::validate::<$sys>();
259+
256260
#[link_section = ".vector_table.interrupts"]
257261
#[no_mangle]
258262
static __INTERRUPTS: $crate::threading::InterruptHandlerTable =

src/constance_port_arm_m/src/threading.rs

Lines changed: 108 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ impl State {
105105
// Safety: Only the port can call this method
106106
let msp_top = unsafe { System::interrupt_stack_top() };
107107

108-
llvm_asm!("
108+
pp_asm!("
109109
# Reset MSP to the top of the stack, effectively discarding the
110110
# current context. Beyond this point, this code is considered to be
111111
# running in the idle task.
@@ -116,9 +116,11 @@ impl State {
116116
# TODO: Set MSPLIM on Armv8-M
117117
118118
# Release CPU Lock
119-
# TODO: Choose the appropriate method based on `CPU_LOCK_PRIORITY_MASK`
120-
mov r0, #0
121-
msr basepri, r0
119+
# TODO: Choose the appropriate method based on `CPU_LOCK_PRIORITY_MASK` "
120+
if cfg!(not(any(armv6m, armv8m_base))) { "
121+
movs r0, #0
122+
msr basepri, r0
123+
" } "
122124
cpsie i
123125
"
124126
:
@@ -154,13 +156,13 @@ impl State {
154156
// Pend PendSV
155157
cortex_m::peripheral::SCB::set_pendsv();
156158

157-
llvm_asm!("
159+
pp_asm!("
158160
# Activate the idle task's context by switching the current SP to
159161
# MSP.
160162
# `running_task` is `None` at this point, so the processor state
161163
# will be consistent with `running_task` after this operation.
162164
mrs r0, control
163-
bic r0, #2
165+
subs r0, #2
164166
msr control, r0
165167
166168
# Transfer the control to the idle task. We have pended PendSV, so
@@ -171,9 +173,17 @@ impl State {
171173
# - `CONTROL.SPSEL == 0` (we just set it)
172174
# - Thread mode (because `exit_and_dispatch` is called in a task
173175
# context),
174-
# - CPU Lock active (`exit_and_dispatch`'s requirement)
175-
b $0
176-
"
176+
# - CPU Lock active (`exit_and_dispatch`'s requirement) "
177+
if cfg!(armv6m) { "
178+
ldr r0, IdleTaskConst
179+
bx r0
180+
181+
.align 2
182+
IdleTaskConst:
183+
.word $0
184+
" } else { "
185+
b $0
186+
" }
177187
:
178188
: "X"(Self::idle_task::<System> as unsafe extern fn() -> !)
179189
:
@@ -216,7 +226,7 @@ impl State {
216226
unsafe { State::leave_cpu_lock_inner::<System>() };
217227
}
218228

219-
llvm_asm!("
229+
pp_asm!("
220230
# Save the context of the previous task
221231
#
222232
# [r0 = &running_task, r4-r11 = context, lr = EXC_RETURN]
@@ -233,15 +243,32 @@ impl State {
233243
#
234244
# [r0 = &running_task]
235245
236-
ldr r1, [r0]
237-
cbz r1, ChooseTask
246+
ldr r1, [r0] "
247+
if cfg!(armv6m) { "
248+
cmp r1, #0
249+
beq ChooseTask
250+
" } else { "
251+
cbz r1, ChooseTask
252+
" } "
238253
mrs r2, psp
239254
mrs r3, control
240-
sub r2, #40
241-
str r2, [r1]
242-
stm r2, {r4-r11}
243-
str lr, [r2, 32]
244-
str r3, [r2, 36]
255+
subs r2, #40
256+
str r2, [r1] "
257+
if cfg!(any(armv6m, armv8m_base)) { "
258+
stm r2!, {r4-r7}
259+
mov r4, r8
260+
mov r5, r9
261+
mov r6, r10
262+
mov r7, r11
263+
stm r2!, {r4-r7}
264+
mov r4, lr
265+
str r4, [r2]
266+
str r3, [r2, 4]
267+
" } else { "
268+
stm r2, {r4-r11}
269+
str lr, [r2, 32]
270+
str r3, [r2, 36]
271+
" } "
245272
246273
# Choose the next task to run
247274
ChooseTask:
@@ -272,20 +299,46 @@ impl State {
272299
#
273300
# [r4-r11 = context, lr = EXC_RETURN]
274301
275-
ldr r1, [r0]
276-
cbz r1, RestoreIdleTask
277-
ldr r2, [r1]
278-
ldr lr, [r2, 32]
279-
ldr r3, [r2, 36]
280-
msr control, r3
281-
ldmia r2, {r4-r11}
282-
add r2, #40
302+
ldr r1, [r0] "
303+
if cfg!(armv6m) { "
304+
cmp r1, #0
305+
beq RestoreIdleTask
306+
" } else { "
307+
cbz r1, RestoreIdleTask
308+
" } "
309+
ldr r2, [r1] "
310+
if cfg!(any(armv6m, armv8m_base)) { "
311+
adds r2, #16
312+
ldmia r2!, {r4-r7}
313+
mov r8, r4
314+
mov r9, r5
315+
mov r10, r6
316+
mov r11, r7
317+
subs r2, #32
318+
ldmia r2!, {r4-r7}
319+
adds r2, #16
320+
ldmia r2!, {r0, r3}
321+
mov lr, r0
322+
" } else { "
323+
ldr lr, [r2, 32]
324+
ldr r3, [r2, 36]
325+
msr control, r3
326+
ldmia r2, {r4-r11}
327+
adds r2, #40
328+
" } "
283329
msr psp, r2
284330
bx lr
285331
286332
RestoreIdleTask:
287-
mov r0, #0
288-
mov lr, #0xfffffff9
333+
movs r0, #0 "
334+
if cfg!(any(armv6m, armv8m_base)) { "
335+
# 0x00000006 = !0xfffffff9
336+
movs r1, #6
337+
mvns r1, r1
338+
mov lr, r1
339+
" } else { "
340+
mov lr, #0xfffffff9
341+
" } "
289342
msr control, r0
290343
"
291344
:
@@ -302,13 +355,15 @@ impl State {
302355

303356
#[inline(always)]
304357
unsafe fn enter_cpu_lock_inner<System: PortInstance>() {
358+
#[cfg(not(any(armv6m, armv8m_base)))]
305359
if System::CPU_LOCK_PRIORITY_MASK > 0 {
306360
// Set `BASEPRI` to `CPU_LOCK_PRIORITY_MASK`
307361
unsafe { cortex_m::register::basepri::write(System::CPU_LOCK_PRIORITY_MASK) };
308-
} else {
309-
// Set `PRIMASK` to `1`
310-
cortex_m::interrupt::disable();
362+
return;
311363
}
364+
365+
// Set `PRIMASK` to `1`
366+
cortex_m::interrupt::disable();
312367
}
313368

314369
#[inline(always)]
@@ -318,13 +373,15 @@ impl State {
318373

319374
#[inline(always)]
320375
unsafe fn leave_cpu_lock_inner<System: PortInstance>() {
376+
#[cfg(not(any(armv6m, armv8m_base)))]
321377
if System::CPU_LOCK_PRIORITY_MASK > 0 {
322378
// Set `BASEPRI` to `0` (no masking)
323379
unsafe { cortex_m::register::basepri::write(0) };
324-
} else {
325-
// Set `PRIMASK` to `0`
326-
unsafe { cortex_m::interrupt::enable() };
380+
return;
327381
}
382+
383+
// Set `PRIMASK` to `0`
384+
unsafe { cortex_m::interrupt::enable() };
328385
}
329386

330387
pub unsafe fn initialize_task_state<System: PortInstance>(
@@ -396,11 +453,12 @@ impl State {
396453

397454
#[inline(always)]
398455
pub fn is_cpu_lock_active<System: PortInstance>(&self) -> bool {
456+
#[cfg(not(any(armv6m, armv8m_base)))]
399457
if System::CPU_LOCK_PRIORITY_MASK > 0 {
400-
cortex_m::register::basepri::read() != 0
401-
} else {
402-
cortex_m::register::primask::read().is_inactive()
458+
return cortex_m::register::basepri::read() != 0;
403459
}
460+
461+
cortex_m::register::primask::read().is_inactive()
404462
}
405463

406464
pub fn is_task_context<System: PortInstance>(&self) -> bool {
@@ -540,15 +598,17 @@ pub union InterruptHandler {
540598
defined: constance::kernel::cfg::InterruptHandlerFn,
541599
}
542600

543-
pub type InterruptHandlerTable = [InterruptHandler; 240];
601+
const NUM_INTERRUPTS: usize = if cfg!(armv6m) { 32 } else { 240 };
602+
603+
pub type InterruptHandlerTable = [InterruptHandler; NUM_INTERRUPTS];
544604

545605
/// Used by `use_port!`
546606
pub const fn make_interrupt_handler_table<System: PortInstance>() -> InterruptHandlerTable
547607
where
548608
// FIXME: Work-around for <https://github.com/rust-lang/rust/issues/43475>
549609
System::TaskReadyQueue: core::borrow::BorrowMut<[StaticListHead<TaskCb<System>>]>,
550610
{
551-
let mut table = [InterruptHandler { undefined: 0 }; 240];
611+
let mut table = [InterruptHandler { undefined: 0 }; NUM_INTERRUPTS];
552612
let mut i = 0;
553613

554614
// FIXME: Work-around for `for` being unsupported in `const fn`
@@ -579,3 +639,13 @@ where
579639

580640
table
581641
}
642+
643+
/// Used by `use_port!`
644+
pub const fn validate<System: PortInstance>() {
645+
#[cfg(any(armv6m, armv8m_base))]
646+
assert!(
647+
System::CPU_LOCK_PRIORITY_MASK == 0,
648+
"`CPU_LOCK_PRIORITY_MASK` must be zero because the target architecture \
649+
does not have a BASEPRI register"
650+
);
651+
}

src/constance_port_arm_m/src/utils.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
//! otherwise. It's exposed only because it's needed by macros.
55
use core::marker::PhantomData;
66

7+
#[macro_use]
8+
mod pptext;
9+
710
/// Conditional type
811
macro_rules! If {
912
( if ($cond:expr) { $t:ty } else { $f:ty } ) => {

0 commit comments

Comments
 (0)