Skip to content

Commit b22c89a

Browse files
committed
[fiber] Add cooperative, stackful fibers
1 parent def26a4 commit b22c89a

File tree

16 files changed

+1128
-1
lines changed

16 files changed

+1128
-1
lines changed

repo.lb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,10 @@ def init(repo):
274274
description=descr_target,
275275
enumeration=devices))
276276

277+
# Invisible option guarding the Fiber API until it is ready
278+
repo.add_option(BooleanOption(name="__fibers", default=False,
279+
description="Enable unstable fiber API."))
280+
277281
def prepare(repo, options):
278282
repo.add_modules_recursive("ext", modulefile="*.lb")
279283
repo.add_modules_recursive("src", modulefile="*.lb")

src/modm/architecture/utils.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272
/// Marks a declaration as deprecated and displays a message.
7373
#define modm_deprecated(msg)
7474

75+
/// Tells the compiler to not generate prologue/epilogue code for this function.
76+
#define modm_naked
77+
7578
/// Places a function in the fastest executable memory:
7679
/// instruction cache, core coupled memory or SRAM as fallback.
7780
#define modm_fastcode
@@ -134,6 +137,7 @@
134137
#define modm_fallthrough __attribute__((fallthrough))
135138
#define modm_noreturn __attribute__((noreturn))
136139
#define modm_warn_unused_result __attribute__((warn_unused_result))
140+
#define modm_naked __attribute__((naked))
137141

138142
#ifdef MODM_COMPILER_MINGW
139143
// FIXME: Windows Object Format PE does not support weak symbols

src/modm/processing/fiber.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*
2+
* Copyright (c) 2020, Erik Henriksson
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#include "fiber/fiber.hpp"
13+
#include "fiber/scheduler.hpp"

src/modm/processing/fiber/context.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2020, Erik Henriksson
3+
* Copyright (c) 2021, Niklas Hauser
4+
*
5+
* This file is part of the modm project.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
10+
*/
11+
// ----------------------------------------------------------------------------
12+
13+
#pragma once
14+
15+
#include <stdint.h>
16+
#include <stddef.h>
17+
#include <modm/architecture/utils.hpp>
18+
19+
#ifdef __cplusplus
20+
extern "C"
21+
{
22+
#endif
23+
24+
struct modm_context_t
25+
{
26+
uintptr_t sp;
27+
size_t stack_size;
28+
};
29+
30+
/// Prepares the stack to jump into function with arg and call end on return
31+
modm_context_t
32+
modm_context_init(uintptr_t stack, uintptr_t arg, uintptr_t fn, uintptr_t end);
33+
34+
/// Switches control from the main context to the user context.
35+
void
36+
modm_context_start(uintptr_t sp);
37+
38+
/// Jumps from the "from" user context to the "to" user context.
39+
void
40+
modm_context_jump(uintptr_t* from_sp, uintptr_t to_sp);
41+
42+
/// Switches control back to the main context from the user context.
43+
void __attribute__((noreturn))
44+
modm_context_end();
45+
46+
#ifdef __cplusplus
47+
}
48+
#endif
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
/*
2+
* Copyright (c) 2020, Erik Henriksson
3+
* Copyright (c) 2021, Niklas Hauser
4+
*
5+
* This file is part of the modm project.
6+
*
7+
* This Source Code Form is subject to the terms of the Mozilla Public
8+
* License, v. 2.0. If a copy of the MPL was not distributed with this
9+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
10+
*/
11+
// ----------------------------------------------------------------------------
12+
13+
#include "context.h"
14+
15+
/* Stack layout (growing downwards):
16+
* Registers r4-r11 must be preserved across subroutine calls.
17+
*
18+
* LR
19+
%% if not cm0
20+
* r11
21+
* r10
22+
* r9
23+
* r8
24+
%% endif
25+
* r7
26+
* r6
27+
* r5
28+
* r4
29+
%% if cm0
30+
* r11
31+
* r10
32+
* r9
33+
* r8
34+
%% endif
35+
%% if with_fpu
36+
* s31
37+
* s30
38+
* s29
39+
* s28
40+
* s27
41+
* s26
42+
* s25
43+
* s24
44+
* s23
45+
* s22
46+
* s21
47+
* s20
48+
* s19
49+
* s18
50+
* s17
51+
* s16
52+
*
53+
* From the PCSAA:
54+
* Registers s16-s31 (d8-d15, q4-q7) must be preserved across subroutine calls;
55+
* registers s0-s15 (d0-d7, q0- q3) do not need to be preserved (and can be used
56+
* for passing arguments or returning results in standard procedure-call
57+
* variants). Registers d16-d31 (q8-q15), if present, do not need to be
58+
* preserved.
59+
%% endif
60+
*/
61+
62+
static void modm_naked
63+
modm_context_entry()
64+
{
65+
asm volatile
66+
(
67+
"pop {r0} \n\t" // Loads return address
68+
"mov lr, r0 \n\t" // Set LR
69+
"pop {r0, pc} \n\t" // Load argument and jump
70+
);
71+
}
72+
73+
modm_context_t
74+
modm_context_init(uintptr_t stack, uintptr_t arg, uintptr_t fn, uintptr_t end)
75+
{
76+
uintptr_t* sp = (uintptr_t*)arg;
77+
*--sp = fn; // actual fiber function
78+
*--sp = arg; // r0 argument
79+
*--sp = end; // called after fn returns
80+
81+
*--sp = (uintptr_t) modm_context_entry;
82+
sp -= 8{% if with_fpu %}+16{% endif %}; // r4-r11{% if with_fpu %}, s16-s31{% endif %}
83+
return {(uintptr_t) sp, arg - stack};
84+
}
85+
86+
#define MODM_PUSH_CONTEXT() \
87+
%% if cm0
88+
"push {r4-r7, lr} \n\t" \
89+
"mov r4, r8 \n\t" \
90+
"mov r5, r9 \n\t" \
91+
"mov r6, r10 \n\t" \
92+
"mov r7, r11 \n\t" \
93+
"push {r4-r7} \n\t"
94+
%% else
95+
"push {r4-r11, lr} \n\t"{% if with_fpu %} \
96+
"vpush {d8-d15} \n\t"{% endif %}
97+
%% endif
98+
%#
99+
#define MODM_POP_CONTEXT() \
100+
%% if cm0
101+
"pop {r4-r7} \n\t" \
102+
"mov r8, r4 \n\t" \
103+
"mov r9, r5 \n\t" \
104+
"mov r10, r6 \n\t" \
105+
"mov r11, r7 \n\t" \
106+
"pop {r4-r7, pc} \n\t"
107+
%% else
108+
%% if with_fpu
109+
"vpop {d8-d15} \n\t" \
110+
%% endif
111+
"pop {r4-r11, pc} \n\t"
112+
%% endif
113+
%#
114+
void modm_naked
115+
modm_context_start(uintptr_t)
116+
{
117+
asm volatile
118+
(
119+
MODM_PUSH_CONTEXT()
120+
121+
"mrs r2, control \n\t"
122+
%% if cm0
123+
"mov r1, #2 \n\t"
124+
"orr r2, r2, r1 \n\t" // Set SPSEL
125+
%% else
126+
"orr r2, r2, #2 \n\t" // Set SPSEL
127+
%% endif
128+
"msr control, r2 \n\t"
129+
130+
"mov sp, r0 \n\t" // Set PSP to fiber stack (to.sp)
131+
132+
MODM_POP_CONTEXT()
133+
);
134+
}
135+
136+
void modm_naked
137+
modm_context_jump(uintptr_t*, uintptr_t)
138+
{
139+
asm volatile
140+
(
141+
MODM_PUSH_CONTEXT()
142+
%#
143+
%% if cm0
144+
"mov r2, sp \n\t"
145+
"str r2, [r0] \n\t" // Store the SP in "from"
146+
%% else
147+
"str sp, [r0] \n\t" // Store the SP in "from"
148+
%% endif
149+
"mov sp, r1 \n\t" // Restore SP from "to"
150+
151+
MODM_POP_CONTEXT()
152+
);
153+
}
154+
155+
void modm_naked
156+
modm_context_end()
157+
{
158+
asm volatile
159+
(
160+
"mrs r0, control \n\t"
161+
%% if cm0
162+
"mov r1, #2 \n\t"
163+
"bic r0, r0, r1 \n\t" // Unset SPSEL
164+
%% else
165+
"bic r0, r0, #2 \n\t" // Unset SPSEL
166+
%% endif
167+
"msr control, r0 \n\t"
168+
169+
MODM_POP_CONTEXT()
170+
);
171+
}

0 commit comments

Comments
 (0)