Skip to content

Commit

Permalink
[fiber] x86_64 support + return from fiber + tests
Browse files Browse the repository at this point in the history
  • Loading branch information
henrikssn committed Sep 6, 2020
1 parent 5a3ac05 commit be3d1d2
Show file tree
Hide file tree
Showing 19 changed files with 502 additions and 58 deletions.
56 changes: 56 additions & 0 deletions examples/linux/fiber/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#include <modm/debug/logger.hpp>
#include <modm/processing.hpp>

#include <chrono>
#include <cmath>

using namespace std::chrono_literals;

#define STACK_SIZE 1024

modm_fiber
void f1() {
MODM_LOG_INFO << "f1" << modm::endl;
modm::yield();
MODM_LOG_INFO << "f1 done" << modm::endl;
modm::done();
}

modm_fiber
void f2() {
MODM_LOG_INFO << "f2" << modm::endl;
modm::yield();
MODM_LOG_INFO << "f2 done" << modm::endl;
modm::done();
}

modm_fiber
void idle() {
MODM_LOG_INFO << "idle" << modm::endl;
modm::yield();
MODM_LOG_INFO << "all done" << modm::endl;
modm::done();
}

modm::fiber::Stack<STACK_SIZE> stack1, stack2, stack_idle;
modm::Fiber fiber1(stack1, &f1), fiber2(stack2, &f2), fiber_idle(stack_idle, &idle);

int main( int argc, char * argv[])
{
MODM_LOG_INFO << "Start" << modm::endl;
modm::fiber::scheduler().start();
// Will never get here.
MODM_LOG_INFO << "End" << modm::endl;
return 0;
}
12 changes: 12 additions & 0 deletions examples/linux/fiber/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<library>
<options>
<option name="modm:target">hosted-darwin</option>
<option name="modm:build:build.path">../../../build/linux/fiber</option>
</options>
<modules>
<module>modm:debug</module>
<module>modm:platform:core</module>
<module>modm:processing:fiber</module>
<module>modm:build:scons</module>
</modules>
</library>
6 changes: 2 additions & 4 deletions examples/samd/fiber/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,15 @@ using namespace std::chrono_literals;
#define STACK_SIZE 40
#endif

modm_fiber

void f1();

modm_fiber

void f2();

modm::fiber::Stack<STACK_SIZE> stack1, stack2;
modm::Fiber fiber1(stack1, &f1), fiber2(stack2, &f2);

modm_fiber
void f1() {
#ifdef MODM_BOARD_HAS_LOGGER
MODM_LOG_INFO << "f1: entered" << modm::endl;
Expand All @@ -45,7 +44,6 @@ void f1() {
}
}

modm_fiber
void f2() {
#ifdef MODM_BOARD_HAS_LOGGER
MODM_LOG_INFO << "f2: entered" << modm::endl;
Expand Down
14 changes: 14 additions & 0 deletions src/modm/board/blue_pill/board.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

#include <modm/platform.hpp>
#include <modm/architecture/interface/clock.hpp>
#include <modm/debug/logger.hpp>
#define MODM_BOARD_HAS_LOGGER

using namespace modm::platform;

Expand Down Expand Up @@ -95,12 +97,24 @@ using Leds = SoftwareGpioPort< LedGreen >;

using Button = GpioUnused;

namespace stlink
{
using Rx = GpioInputA3;
using Tx = GpioOutputA2;
using Uart = Usart2;
}

using LoggerDevice = modm::IODeviceWrapper< stlink::Uart, modm::IOBuffer::BlockIfFull >;

inline void
initialize()
{
SystemClock::enable();
SysTickTimer::initialize<SystemClock>();

stlink::Uart::connect<stlink::Tx::Tx, stlink::Rx::Rx>();
stlink::Uart::initialize<SystemClock, 115200_Bd>();

LedGreen::setOutput(modm::Gpio::Low);
}

Expand Down
6 changes: 4 additions & 2 deletions src/modm/board/blue_pill/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,17 @@ def prepare(module, options):

module.depends(
":architecture:clock",
":debug",
":platform:clock",
":platform:core",
":platform:gpio")
":platform:gpio",
":platform:uart:2")
return True

def build(env):
env.outbasepath = "modm/src/modm/board"
env.substitutions = {
"with_logger": False,
"with_logger": True,
"with_assert": env.has_module(":architecture:assert")
}
env.template("../board.cpp.in", "board.cpp")
Expand Down
4 changes: 2 additions & 2 deletions src/modm/board/feather_m0/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ def prepare(module, options):
def build(env):
env.outbasepath = "modm/src/modm/board"
env.substitutions = {
"with_logger": False,
"with_assert": False,
"with_logger": True,
"with_assert": True,
}
env.template("../board.cpp.in", "board.cpp")
env.template("board.hpp.in", "board.hpp")
15 changes: 15 additions & 0 deletions src/modm/processing/fiber/context.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2020, Erik Henriksson
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------


#include "context.hpp"

modm_context main_context;
26 changes: 13 additions & 13 deletions src/modm/processing/fiber/context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,33 +15,33 @@

#include <cstddef>

typedef uint32_t modm_stack_t;
typedef void* modm_stack_t;

struct modm_context {
modm_stack_t* sp;
std::size_t stack_size = 0;
};

extern modm_context main_context;

/* Prepares the stack to look like the "from" arg after modm_jumpcontext as run. */
extern "C"
modm_always_inline
modm_context
modm_makecontext(modm_stack_t* stack, std::size_t stack_size, void (*fn)(void)) {
modm_stack_t* sp = stack + stack_size / sizeof(modm_stack_t) - 1;
*sp = (modm_stack_t) fn;
return {sp, stack_size};
}

/* Switches control from the main thread to the user thread. */
extern "C"
modm_makecontext(modm_stack_t* stack, std::size_t stack_size, void (*fn)(void), void (*end)(void));

/* Switches control from the main context to the user context. */
modm_always_inline
void
modm_startcontext(const modm_context to);

/* Jumps from the "from" context to the "to" context. */
extern "C"
/* Jumps from the "from" user context to the "to" user context. */
modm_always_inline
void
modm_jumpcontext(modm_context* from, const modm_context to);

#include "context_cortex_impl.hpp"
/* Switches control back to the main context from the user context. */
modm_always_inline
void
modm_endcontext();

#include "context_impl.hpp"
114 changes: 102 additions & 12 deletions src/modm/processing/fiber/context_cortex_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,129 @@
*/
// ----------------------------------------------------------------------------

extern "C"
modm_always_inline
#include <modm/platform/device.hpp>
#include <modm/debug/logger.hpp>

// Stack layout:
// r8
// r9
// r10
// r11
// r4
// r5
// r6
// r7
// LR
// PC


modm_context
modm_makecontext(modm_stack_t* stack, std::size_t stack_size,
void (*fn)(void), void (*end)(void)) {
modm_stack_t* sp = stack + stack_size / sizeof(modm_stack_t);
*--sp = (modm_stack_t) fn; // PC
*--sp = (modm_stack_t) end; // LR
sp -= 8; // r4-r11
return {sp, stack_size};
}

void
modm_startcontext(const modm_context to) {
modm_stack_t** main_sp = &main_context.sp;
modm_stack_t* to_sp = to.sp;
asm volatile(
"adr r3, 1f\n\t" // Load address of instruction after "pop {pc}" into r3
"add r3, r3, #1\n\t" // Stay in thumb mode
"push {r3}\n\t" // Save instruction address to stack (to be used for PC later)

"push {r4-r7, lr}\n\t"
"mov r4, r8\n\t"
"mov r5, r9\n\t"
"mov r6, r10\n\t"
"mov r7, r11\n\t"
"push {r4-r7}\n\t"

"mov r3, sp\n\t"
"str r3, [%[main_sp]]\n\t" // Store the main SP in "main_sp"
"msr psp, %[to_sp]\n\t" // Set PSP to top of stack
"mrs r1, control\n\t"
"mrs r3, control\n\t"
"mov r2, #0x2\n\t" // Set SPSEL
"orr r1, r1, r2\n\t"
"msr control, r1\n\t"
"orr r3, r2\n\t"
"msr control, r3\n\t"

"pop {r4-r7}\n\t"
"mov r8, r4\n\t"
"mov r9, r5\n\t"
"mov r10, r6\n\t"
"mov r11, r7\n\t"
"pop {r4-r7}\n\t"
"pop {r3}\n\t"
"mov lr, r3\n\t"

"pop {pc}\n\t" // Perform the jump
/*outputs*/: [to_sp] "+r" (to_sp)
".align 2\n\t"
"1:\n\t"
/*outputs*/: [main_sp] "+r" (main_sp), [to_sp] "+r" (to_sp)
/*inputs*/:
/*clobbers*/: "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "memory");
/*clobbers*/: "r2", "r3", "memory");
}

extern "C"
void
modm_jumpcontext(modm_context* from, const modm_context to) {
modm_stack_t** from_sp = &from->sp;
modm_stack_t* to_sp = to.sp;
register modm_stack_t** from_sp asm("r0") = &from->sp;
register modm_stack_t* to_sp asm("r1") = to.sp;
asm volatile(
"adr r3, 1f\n\t" // Load address of instruction after "pop {pc}" into r3
"add r3, r3, #1\n\t" // Stay in thumb mode
"push {r3}\n\t" // Push instruction address to stack (to be used for PC later)
"push {r3}\n\t" // Save instruction address to stack (to be used for PC later)

"push {r4-r7, lr}\n\t"
"mov r4, r8\n\t"
"mov r5, r9\n\t"
"mov r6, r10\n\t"
"mov r7, r11\n\t"
"push {r4-r7}\n\t"

"mov r3, sp\n\t"
"str r3, [%[from_sp]]\n\t" // Store the SP in "from"
"mov sp, %[to_sp]\n\t" // Restore SP from "to"

"pop {r4-r7}\n\t"
"mov r8, r4\n\t"
"mov r9, r5\n\t"
"mov r10, r6\n\t"
"mov r11, r7\n\t"
"pop {r4-r7}\n\t"
"pop {r3}\n\t"
"mov lr, r3\n\t"

"pop {pc}\n\t" // Perform the jump
".align 2\n\t"
"1:\n\t"
/*outputs*/: [from_sp] "+r" (from_sp), [to_sp] "+r" (to_sp)
/*inputs*/:
/*clobbers*/: "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", "memory");
/*clobbers*/: "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "memory");
}

void
modm_endcontext() {
asm volatile(
"mrs r1, control\n\t"
"mov r2, #0x2\n\t" // Unset SPSEL
"bic r1, r1, r2\n\t"
"msr control, r1\n\t"

"pop {r4-r7}\n\t"
"mov r8, r4\n\t"
"mov r9, r5\n\t"
"mov r10, r6\n\t"
"mov r11, r7\n\t"
"pop {r4-r7}\n\t"
"pop {r3}\n\t"
"mov lr, r3\n\t"

"pop {pc}\n\t" // Perform the jump
/*outputs*/:
/*inputs*/:
/*clobbers*/: "r1", "r2", "memory");
}
Loading

0 comments on commit be3d1d2

Please sign in to comment.