1// +build scheduler.tasks,avr 2 3package task 4 5import "unsafe" 6 7const stackSize = 256 8 9// calleeSavedRegs is the list of registers that must be saved and restored when 10// switching between tasks. Also see scheduler_avr.S that relies on the 11// exact layout of this struct. 12// 13// https://gcc.gnu.org/wiki/avr-gcc#Call-Saved_Registers 14type calleeSavedRegs struct { 15 r2r3 uintptr 16 r4r5 uintptr 17 r6r7 uintptr 18 r8r9 uintptr 19 r10r11 uintptr 20 r12r13 uintptr 21 r14r15 uintptr 22 r16r17 uintptr 23 r28r29 uintptr // Y register 24 25 pc uintptr 26} 27 28// registers gets a pointer to the registers stored at the top of the stack. 29func (s *state) registers() *calleeSavedRegs { 30 return (*calleeSavedRegs)(unsafe.Pointer(s.sp + 1)) 31} 32 33// startTask is a small wrapper function that sets up the first (and only) 34// argument to the new goroutine and makes sure it is exited when the goroutine 35// finishes. 36//go:extern tinygo_startTask 37var startTask [0]uint8 38 39// archInit runs architecture-specific setup for the goroutine startup. 40// Note: adding //go:noinline to work around an AVR backend bug. 41//go:noinline 42func (s *state) archInit(stack []uintptr, fn uintptr, args unsafe.Pointer) { 43 // Set up the stack canary, a random number that should be checked when 44 // switching from the task back to the scheduler. The stack canary pointer 45 // points to the first word of the stack. If it has changed between now and 46 // the next stack switch, there was a stack overflow. 47 s.canaryPtr = &stack[0] 48 *s.canaryPtr = stackCanary 49 50 // Store the initial sp for the startTask function (implemented in assembly). 51 s.sp = uintptr(unsafe.Pointer(&stack[uintptr(len(stack))-(unsafe.Sizeof(calleeSavedRegs{})/unsafe.Sizeof(uintptr(0)))])) - 1 52 53 // Initialize the registers. 54 // These will be popped off of the stack on the first resume of the goroutine. 55 r := s.registers() 56 57 // Start the function at tinygo_startTask. 58 startTask := uintptr(unsafe.Pointer(&startTask)) 59 r.pc = startTask/2>>8 | startTask/2<<8 60 61 // Pass the function to call in r2:r3. 62 // This function is a compiler-generated wrapper which loads arguments out 63 // of a struct pointer. See createGoroutineStartWrapper (defined in 64 // compiler/goroutine.go) for more information. 65 r.r2r3 = fn 66 67 // Pass the pointer to the arguments struct in r4:45. 68 r.r4r5 = uintptr(args) 69} 70 71func (s *state) resume() { 72 switchToTask(s.sp) 73} 74 75//export tinygo_switchToTask 76func switchToTask(uintptr) 77 78//export tinygo_switchToScheduler 79func switchToScheduler(*uintptr) 80 81func (s *state) pause() { 82 switchToScheduler(&s.sp) 83} 84 85//export tinygo_pause 86func pause() { 87 Pause() 88} 89