riscv: switch to tasks-based scheduler
This is only supported for RV32 at the moment. RV64 can be added at a later time.
Этот коммит содержится в:
родитель
5d8f25a622
коммит
878b62bbe8
5 изменённых файлов: 139 добавлений и 1 удалений
|
@ -1,4 +1,4 @@
|
||||||
// +build scheduler.tasks,arm,!cortexm,!avr,!xtensa
|
// +build scheduler.tasks,arm,!cortexm,!avr,!xtensa,!tinygo.riscv
|
||||||
|
|
||||||
package task
|
package task
|
||||||
|
|
||||||
|
|
69
src/internal/task/task_stack_tinygoriscv.S
Обычный файл
69
src/internal/task/task_stack_tinygoriscv.S
Обычный файл
|
@ -0,0 +1,69 @@
|
||||||
|
.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, s0 contains the pc of the to-be-started function and s1
|
||||||
|
// 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.
|
||||||
|
mv a0, s1
|
||||||
|
|
||||||
|
// Branch to the "goroutine start" function. Use jalr to write the return
|
||||||
|
// address to ra so we'll return here after the goroutine exits.
|
||||||
|
jalr s0
|
||||||
|
|
||||||
|
// After return, exit this goroutine. This is a tail call.
|
||||||
|
tail tinygo_pause
|
||||||
|
|
||||||
|
.section .text.tinygo_swapTask
|
||||||
|
.global tinygo_swapTask
|
||||||
|
.type tinygo_swapTask, %function
|
||||||
|
tinygo_swapTask:
|
||||||
|
// This function gets the following parameters:
|
||||||
|
// a0 = newStack uintptr
|
||||||
|
// a1 = oldStack *uintptr
|
||||||
|
|
||||||
|
// Push all callee-saved registers.
|
||||||
|
addi sp, sp, -52
|
||||||
|
sw ra, 48(sp)
|
||||||
|
sw s11, 44(sp)
|
||||||
|
sw s10, 40(sp)
|
||||||
|
sw s9, 36(sp)
|
||||||
|
sw s8, 32(sp)
|
||||||
|
sw s7, 28(sp)
|
||||||
|
sw s6, 24(sp)
|
||||||
|
sw s5, 20(sp)
|
||||||
|
sw s4, 16(sp)
|
||||||
|
sw s3, 12(sp)
|
||||||
|
sw s2, 8(sp)
|
||||||
|
sw s1, 4(sp)
|
||||||
|
sw s0, (sp)
|
||||||
|
|
||||||
|
// Save the current stack pointer in oldStack.
|
||||||
|
sw sp, 0(a1)
|
||||||
|
|
||||||
|
// Switch to the new stack pointer.
|
||||||
|
mv sp, a0
|
||||||
|
|
||||||
|
// Pop all saved registers from this new stack.
|
||||||
|
lw ra, 48(sp)
|
||||||
|
lw s11, 44(sp)
|
||||||
|
lw s10, 40(sp)
|
||||||
|
lw s9, 36(sp)
|
||||||
|
lw s8, 32(sp)
|
||||||
|
lw s7, 28(sp)
|
||||||
|
lw s6, 24(sp)
|
||||||
|
lw s5, 20(sp)
|
||||||
|
lw s4, 16(sp)
|
||||||
|
lw s3, 12(sp)
|
||||||
|
lw s2, 8(sp)
|
||||||
|
lw s1, 4(sp)
|
||||||
|
lw s0, (sp)
|
||||||
|
addi sp, sp, 52
|
||||||
|
|
||||||
|
// Return into the task.
|
||||||
|
ret
|
66
src/internal/task/task_stack_tinygoriscv.go
Обычный файл
66
src/internal/task/task_stack_tinygoriscv.go
Обычный файл
|
@ -0,0 +1,66 @@
|
||||||
|
// +build scheduler.tasks,tinygo.riscv
|
||||||
|
|
||||||
|
package task
|
||||||
|
|
||||||
|
import "unsafe"
|
||||||
|
|
||||||
|
var systemStack uintptr
|
||||||
|
|
||||||
|
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||||
|
// switching between tasks. Also see scheduler_riscv.S that relies on the
|
||||||
|
// exact layout of this struct.
|
||||||
|
type calleeSavedRegs struct {
|
||||||
|
s0 uintptr // x8 (fp)
|
||||||
|
s1 uintptr // x9
|
||||||
|
s2 uintptr // x18
|
||||||
|
s3 uintptr // x19
|
||||||
|
s4 uintptr // x20
|
||||||
|
s5 uintptr // x21
|
||||||
|
s6 uintptr // x22
|
||||||
|
s7 uintptr // x23
|
||||||
|
s8 uintptr // x24
|
||||||
|
s9 uintptr // x25
|
||||||
|
s10 uintptr // x26
|
||||||
|
s11 uintptr // x27
|
||||||
|
|
||||||
|
pc uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// archInit runs architecture-specific setup for the goroutine startup.
|
||||||
|
func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
||||||
|
// Store the initial sp for the startTask function (implemented in assembly).
|
||||||
|
s.sp = uintptr(unsafe.Pointer(r))
|
||||||
|
|
||||||
|
// Initialize the registers.
|
||||||
|
// These will be popped off of the stack on the first resume of the goroutine.
|
||||||
|
|
||||||
|
// Start the function at tinygo_startTask (defined in src/internal/task/task_stack_riscv.S).
|
||||||
|
// This assembly code calls a function (passed in s0) with a single argument
|
||||||
|
// (passed in s1). After the function returns, it calls Pause().
|
||||||
|
r.pc = uintptr(unsafe.Pointer(&startTask))
|
||||||
|
|
||||||
|
// Pass the function to call in s0.
|
||||||
|
// This function is a compiler-generated wrapper which loads arguments out
|
||||||
|
// of a struct pointer. See createGoroutineStartWrapper (defined in
|
||||||
|
// compiler/goroutine.go) for more information.
|
||||||
|
r.s0 = fn
|
||||||
|
|
||||||
|
// Pass the pointer to the arguments struct in s1.
|
||||||
|
r.s1 = uintptr(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state) resume() {
|
||||||
|
swapTask(s.sp, &systemStack)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state) pause() {
|
||||||
|
newStack := systemStack
|
||||||
|
systemStack = 0
|
||||||
|
swapTask(newStack, &s.sp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemStack returns the system stack pointer when called from a task stack.
|
||||||
|
// When called from the system stack, it returns 0.
|
||||||
|
func SystemStack() uintptr {
|
||||||
|
return systemStack
|
||||||
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
],
|
],
|
||||||
"extra-files": [
|
"extra-files": [
|
||||||
"src/device/riscv/start.S",
|
"src/device/riscv/start.S",
|
||||||
|
"src/internal/task/task_stack_tinygoriscv.S",
|
||||||
"src/runtime/gc_riscv.S",
|
"src/runtime/gc_riscv.S",
|
||||||
"src/device/riscv/handleinterrupt.S"
|
"src/device/riscv/handleinterrupt.S"
|
||||||
],
|
],
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
"inherits": ["riscv"],
|
"inherits": ["riscv"],
|
||||||
"llvm-target": "riscv32--none",
|
"llvm-target": "riscv32--none",
|
||||||
"build-tags": ["tinygo.riscv32"],
|
"build-tags": ["tinygo.riscv32"],
|
||||||
|
"scheduler": "tasks",
|
||||||
|
"default-stack-size": 2048,
|
||||||
"cflags": [
|
"cflags": [
|
||||||
"-march=rv32imac",
|
"-march=rv32imac",
|
||||||
"-mabi=ilp32"
|
"-mabi=ilp32"
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче