github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/internal/task/task_stack_avr.go (about)

     1  //go:build scheduler.tasks && avr
     2  
     3  package task
     4  
     5  import "unsafe"
     6  
     7  //go:extern tinygo_systemStack
     8  var systemStack uintptr
     9  
    10  // calleeSavedRegs is the list of registers that must be saved and restored when
    11  // switching between tasks. Also see task_stack_avr.S that relies on the exact
    12  // layout of this struct.
    13  //
    14  // https://gcc.gnu.org/wiki/avr-gcc#Call-Saved_Registers
    15  type calleeSavedRegs struct {
    16  	r2r3   uintptr
    17  	r4r5   uintptr
    18  	r6r7   uintptr
    19  	r8r9   uintptr
    20  	r10r11 uintptr
    21  	r12r13 uintptr
    22  	r14r15 uintptr
    23  	r16r17 uintptr
    24  	r28r29 uintptr // Y register
    25  
    26  	pc uintptr
    27  }
    28  
    29  // archInit runs architecture-specific setup for the goroutine startup.
    30  // Note: adding //go:noinline to work around an AVR backend bug.
    31  //
    32  //go:noinline
    33  func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
    34  	// Store the initial sp for the startTask function (implemented in assembly).
    35  	s.sp = uintptr(unsafe.Pointer(r)) - 1
    36  
    37  	// Initialize the registers.
    38  	// These will be popped off of the stack on the first resume of the goroutine.
    39  
    40  	// Start the function at tinygo_startTask.
    41  	startTask := uintptr(unsafe.Pointer(&startTask))
    42  	r.pc = startTask/2>>8 | startTask/2<<8
    43  
    44  	// Pass the function to call in r2:r3.
    45  	// This function is a compiler-generated wrapper which loads arguments out
    46  	// of a struct pointer. See createGoroutineStartWrapper (defined in
    47  	// compiler/goroutine.go) for more information.
    48  	r.r2r3 = fn
    49  
    50  	// Pass the pointer to the arguments struct in r4:45.
    51  	r.r4r5 = uintptr(args)
    52  }
    53  
    54  func (s *state) resume() {
    55  	swapTask(s.sp, &systemStack)
    56  }
    57  
    58  func (s *state) pause() {
    59  	newStack := systemStack
    60  	systemStack = 0
    61  	swapTask(newStack, &s.sp)
    62  }
    63  
    64  // SystemStack returns the system stack pointer when called from a task stack.
    65  // When called from the system stack, it returns 0.
    66  func SystemStack() uintptr {
    67  	return systemStack
    68  }