Files
tinygo/src/runtime/scheduler_cortexm.S
T
Ayke van Laethem 542135c357 compiler,runtime: implement stack-based scheduler
This scheduler is intended to live along the (stackless) coroutine based
scheduler which is needed for WebAssembly and unsupported platforms. The
stack based scheduler is somewhat simpler in implementation as it does
not require full program transform passes and supports things like
function pointers and interface methods out of the box with no changes.

Code size is reduced in most cases, even in the case where no scheduler
scheduler is used at all. I'm not exactly sure why but these changes
likely allowed some further optimizations somewhere. Even RAM is
slightly reduced, perhaps some global was elminated in the process as
well.
2019-08-15 17:31:54 +02:00

95 lines
2.8 KiB
ArmAsm

.section .text.tinygo_startTask
.global tinygo_startTask
.type tinygo_startTask, %function
tinygo_startTask:
// Small assembly stub for starting a goroutine. This is already run on the
// new stack, with the callee-saved registers already loaded.
// Most importantly, r4 contains the pc of the to-be-started function and r5
// contains the only argument it is given. Multiple arguments are packed
// into one by storing them in a new allocation.
// Set the first argument of the goroutine start wrapper, which contains all
// the arguments.
mov r0, r5
// Branch to the "goroutine start" function. By using blx instead of bx,
// we'll return here instead of tail calling.
blx r4
// After return, exit this goroutine. This is a tail call.
bl runtime.Goexit
.section .text.tinygo_swapTask
.global tinygo_swapTask
.type tinygo_swapTask, %function
tinygo_swapTask:
// r0 = oldTask *task
// r1 = newTask *task
// This function stores the current register state to a task struct and
// loads the state of another task to replace the current state. Apart from
// saving and restoring all relevant callee-saved registers, it also ends
// with branching to the last program counter (saved as the lr register, to
// follow the ARM calling convention).
// On pre-Thumb2 CPUs (Cortex-M0 in particular), registers r8-r15 cannot be
// used directly. Only very few operations work on them, such as mov. That's
// why the higher register values are first stored in the temporary register
// r3 when loading/storing them.
// Store state to old task. It saves the lr instead of the pc, because that
// will be the pc after returning back to the old task (in a different
// invocation of swapTask).
str r4, [r0, #0]
str r5, [r0, #4]
str r6, [r0, #8]
str r7, [r0, #12]
#if defined(__thumb2__)
str r8, [r0, #16]
str r9, [r0, #20]
str r10, [r0, #24]
str r11, [r0, #28]
str sp, [r0, #32]
str lr, [r0, #36]
#else
mov r3, r8
str r3, [r0, #16]
mov r3, r9
str r3, [r0, #20]
mov r3, r10
str r3, [r0, #24]
mov r3, r11
str r3, [r0, #28]
mov r3, sp
str r3, [r0, #32]
mov r3, lr
str r3, [r0, #36]
#endif
// Load state from new task and branch to the previous position in the
// program.
ldr r4, [r1, #0]
ldr r5, [r1, #4]
ldr r6, [r1, #8]
ldr r7, [r1, #12]
#if defined(__thumb2__)
ldr r8, [r1, #16]
ldr r9, [r1, #20]
ldr r10, [r1, #24]
ldr r11, [r1, #28]
ldr sp, [r1, #32]
#else
ldr r3, [r1, #16]
mov r8, r3
ldr r3, [r1, #20]
mov r9, r3
ldr r3, [r1, #24]
mov r10, r3
ldr r3, [r1, #28]
mov r11, r3
ldr r3, [r1, #32]
mov sp, r3
#endif
ldr r3, [r1, #36]
bx r3