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

     1  //go:build scheduler.tasks && cortexm
     2  
     3  package task
     4  
     5  // Note that this is almost the same as task_stack_arm.go, but it uses the MSP
     6  // register to store the system stack pointer instead of a global variable. The
     7  // big advantage of this is that interrupts always execute with MSP (and not
     8  // PSP, which is used for goroutines) so that goroutines do not need extra stack
     9  // space for interrupts.
    10  
    11  import "C"
    12  import (
    13  	"unsafe"
    14  )
    15  
    16  // calleeSavedRegs is the list of registers that must be saved and restored when
    17  // switching between tasks. Also see task_stack_cortexm.S that relies on the
    18  // exact layout of this struct.
    19  type calleeSavedRegs struct {
    20  	r4  uintptr
    21  	r5  uintptr
    22  	r6  uintptr
    23  	r7  uintptr
    24  	r8  uintptr
    25  	r9  uintptr
    26  	r10 uintptr
    27  	r11 uintptr
    28  
    29  	pc uintptr
    30  }
    31  
    32  // archInit runs architecture-specific setup for the goroutine startup.
    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))
    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 (defined in src/internal/task/task_stack_cortexm.S).
    41  	// This assembly code calls a function (passed in r4) with a single argument (passed in r5).
    42  	// After the function returns, it calls Pause().
    43  	r.pc = uintptr(unsafe.Pointer(&startTask))
    44  
    45  	// Pass the function to call in r4.
    46  	// This function is a compiler-generated wrapper which loads arguments out of a struct pointer.
    47  	// See createGoroutineStartWrapper (defined in compiler/goroutine.go) for more information.
    48  	r.r4 = fn
    49  
    50  	// Pass the pointer to the arguments struct in r5.
    51  	r.r5 = uintptr(args)
    52  }
    53  
    54  func (s *state) resume() {
    55  	tinygo_switchToTask(s.sp)
    56  }
    57  
    58  //export tinygo_switchToTask
    59  func tinygo_switchToTask(uintptr)
    60  
    61  //export tinygo_switchToScheduler
    62  func tinygo_switchToScheduler(*uintptr)
    63  
    64  func (s *state) pause() {
    65  	tinygo_switchToScheduler(&s.sp)
    66  }
    67  
    68  // SystemStack returns the system stack pointer. On Cortex-M, it is always
    69  // available.
    70  //
    71  //export SystemStack
    72  func SystemStack() uintptr