github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/internal/task/task_stack_esp8266.go (about) 1 //go:build scheduler.tasks && esp8266 2 3 package task 4 5 // Stack switch implementation for the ESP8266, which does not use the windowed 6 // ABI of Xtensa. Registers are assigned as follows: 7 // a0: return address (link register) 8 // a1: stack pointer (must be 16-byte aligned) 9 // a2-a7: incoming arguments 10 // a8: static chain (unused) 11 // a12-a15: callee-saved 12 // a15: stack frame pointer (optional, unused) 13 // Sources: 14 // http://cholla.mmto.org/esp8266/xtensa.html 15 // https://0x04.net/~mwk/doc/xtensa.pdf 16 17 import "unsafe" 18 19 var systemStack uintptr 20 21 // calleeSavedRegs is the list of registers that must be saved and restored when 22 // switching between tasks. Also see task_stack_esp8266.S that relies on the 23 // exact layout of this struct. 24 type calleeSavedRegs struct { 25 a12 uintptr 26 a13 uintptr 27 a14 uintptr 28 a15 uintptr 29 30 pc uintptr // also link register or r0 31 } 32 33 // archInit runs architecture-specific setup for the goroutine startup. 34 func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) { 35 // Store the initial sp for the startTask function (implemented in assembly). 36 s.sp = uintptr(unsafe.Pointer(r)) 37 38 // Initialize the registers. 39 // These will be popped off of the stack on the first resume of the goroutine. 40 41 // Start the function at tinygo_startTask (defined in 42 // src/internal/task/task_stack_esp8266.S). 43 // This assembly code calls a function (passed in a12) with a single argument 44 // (passed in a13). After the function returns, it calls Pause(). 45 r.pc = uintptr(unsafe.Pointer(&startTask)) 46 47 // Pass the function to call in a12. 48 // This function is a compiler-generated wrapper which loads arguments out of a struct pointer. 49 // See createGoroutineStartWrapper (defined in compiler/goroutine.go) for more information. 50 r.a12 = fn 51 52 // Pass the pointer to the arguments struct in a13. 53 r.a13 = uintptr(args) 54 } 55 56 func (s *state) resume() { 57 swapTask(s.sp, &systemStack) 58 } 59 60 func (s *state) pause() { 61 newStack := systemStack 62 systemStack = 0 63 swapTask(newStack, &s.sp) 64 } 65 66 // SystemStack returns the system stack pointer when called from a task stack. 67 // When called from the system stack, it returns 0. 68 func SystemStack() uintptr { 69 return systemStack 70 }