mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-09 05:23:40 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f0391eac25 | |||
| 05cdde162c | |||
| 25c8d3ec3a |
@@ -1,3 +1,58 @@
|
|||||||
|
0.25.0
|
||||||
|
---
|
||||||
|
|
||||||
|
* **command line**
|
||||||
|
- change to ignore PortReset failures
|
||||||
|
* **compiler**
|
||||||
|
- `compiler`: darwin/arm64 is aarch64, not arm
|
||||||
|
- `compiler`: don't clobber X18 and FP registers on darwin/arm64
|
||||||
|
- `compiler`: fix issue with methods on generic structs
|
||||||
|
- `compiler`: do not try to build generic functions
|
||||||
|
- `compiler`: fix type names for generic named structs
|
||||||
|
- `compiler`: fix multiple defined function issue for generic functions
|
||||||
|
- `compiler`: implement `unsafe.Alignof` and `unsafe.Sizeof` for generic code
|
||||||
|
* **standard library**
|
||||||
|
- `machine`: add DTR and RTS to Serialer interface
|
||||||
|
- `machine`: reorder pin definitions to improve pin list on tinygo.org
|
||||||
|
- `machine/usb`: add support for MIDI
|
||||||
|
- `machine/usb`: adjust buffer alignment (samd21, samd51, nrf52840)
|
||||||
|
- `machine/usb/midi`: add `NoteOn`, `NoteOff`, and `SendCC` methods
|
||||||
|
- `machine/usb/midi`: add definition of MIDI note number
|
||||||
|
- `runtime`: add benchmarks for memhash
|
||||||
|
- `runtime`: add support for printing slices via print/println
|
||||||
|
* **targets**
|
||||||
|
- `avr`: fix some apparent mistake in atmega1280/atmega2560 pin constants
|
||||||
|
- `esp32`: provide hardware pin constants
|
||||||
|
- `esp32`: fix WDT reset on the MCH2022 badge
|
||||||
|
- `esp32`: optimize SPI transmit
|
||||||
|
- `esp32c3`: provide hardware pin constants
|
||||||
|
- `esp8266`: provide hardware pin constants like `GPIO2`
|
||||||
|
- `nrf51`: define and use `P0_xx` constants
|
||||||
|
- `nrf52840`, `samd21`, `samd51`: unify bootloader entry process
|
||||||
|
- `nrf52840`, `samd21`, `samd51`: change usbSetup and sendZlp to public
|
||||||
|
- `nrf52840`, `samd21`, `samd51`: refactor handleStandardSetup and initEndpoint
|
||||||
|
- `nrf52840`, `samd21`, `samd51`: improve usb-device initialization
|
||||||
|
- `nrf52840`, `samd21`, `samd51`: move usbcdc to machine/usb/cdc
|
||||||
|
- `rp2040`: add usb serial vendor/product ID
|
||||||
|
- `rp2040`: add support for usb
|
||||||
|
- `rp2040`: change default for serial to usb
|
||||||
|
- `rp2040`: add support for `machine.EnterBootloader`
|
||||||
|
- `rp2040`: turn off pullup/down when input type is not specified
|
||||||
|
- `rp2040`: make picoprobe default openocd interface
|
||||||
|
- `samd51`: add support for `DAC1`
|
||||||
|
- `samd51`: improve TRNG
|
||||||
|
- `wasm`: stub `runtime.buffered`, `runtime.getchar`
|
||||||
|
- `wasi`: make leveldb runtime hash the default
|
||||||
|
* **boards**
|
||||||
|
- add Challenger RP2040 LoRa
|
||||||
|
- add MCH2022 badge
|
||||||
|
- add XIAO RP2040
|
||||||
|
- `clue`: remove pins `D21`..`D28`
|
||||||
|
- `feather-rp2040`, `macropad-rp2040`: fix qspi-flash settings
|
||||||
|
- `xiao-ble`: add support for flash-1200-bps-reset
|
||||||
|
- `gopherbot`, `gopherbot2`: add these aliases to simplify for newer users
|
||||||
|
|
||||||
|
|
||||||
0.24.0
|
0.24.0
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+3
-13
@@ -1228,15 +1228,10 @@ func determineStackSizes(mod llvm.Module, executable string) ([]string, map[stri
|
|||||||
// Goroutines need to be started and finished and take up some stack space
|
// Goroutines need to be started and finished and take up some stack space
|
||||||
// that way. This can be measured by measuing the stack size of
|
// that way. This can be measured by measuing the stack size of
|
||||||
// tinygo_startTask.
|
// tinygo_startTask.
|
||||||
var baseStackSize uint64
|
if numFuncs := len(functions["tinygo_startTask"]); numFuncs != 1 {
|
||||||
var baseStackSizeType stacksize.SizeType
|
return nil, nil, fmt.Errorf("expected exactly one definition of tinygo_startTask, got %d", numFuncs)
|
||||||
var baseStackSizeFailedAt *stacksize.CallNode
|
|
||||||
if len(gowrappers) != 0 {
|
|
||||||
if numFuncs := len(functions["tinygo_startTask"]); numFuncs != 1 {
|
|
||||||
return nil, nil, fmt.Errorf("expected exactly one definition of tinygo_startTask, got %d", numFuncs)
|
|
||||||
}
|
|
||||||
baseStackSize, baseStackSizeType, baseStackSizeFailedAt = functions["tinygo_startTask"][0].StackSize()
|
|
||||||
}
|
}
|
||||||
|
baseStackSize, baseStackSizeType, baseStackSizeFailedAt := functions["tinygo_startTask"][0].StackSize()
|
||||||
|
|
||||||
sizes := make(map[string]functionStackSize)
|
sizes := make(map[string]functionStackSize)
|
||||||
|
|
||||||
@@ -1308,11 +1303,6 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if data == nil {
|
|
||||||
// The .tinygo_stacksizes section doesn't exist, so assume this
|
|
||||||
// modification isn't needed.
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(stackSizeLoads)*4 != len(data) {
|
if len(stackSizeLoads)*4 != len(data) {
|
||||||
// Note: while AVR should use 2 byte stack sizes, even 64-bit platforms
|
// Note: while AVR should use 2 byte stack sizes, even 64-bit platforms
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ func getElfSectionData(executable string, sectionName string) ([]byte, elf.FileH
|
|||||||
|
|
||||||
section := elfFile.Section(sectionName)
|
section := elfFile.Section(sectionName)
|
||||||
if section == nil {
|
if section == nil {
|
||||||
return nil, elf.FileHeader{}, nil
|
return nil, elf.FileHeader{}, fmt.Errorf("could not find %s section", sectionName)
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := section.Data()
|
data, err := section.Data()
|
||||||
|
|||||||
+10
-1
@@ -1039,9 +1039,17 @@ func (b *builder) createFunctionStart() {
|
|||||||
b.addError(b.fn.Pos(), errValue)
|
b.addError(b.fn.Pos(), errValue)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
b.addStandardDefinedAttributes(b.llvmFn)
|
b.addStandardDefinedAttributes(b.llvmFn)
|
||||||
if !b.info.exported {
|
if !b.info.exported {
|
||||||
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
// Do not set visibility for local linkage (internal or private).
|
||||||
|
// Otherwise a "local linkage requires default visibility"
|
||||||
|
// assertion error in llvm-project/llvm/include/llvm/IR/GlobalValue.h:236
|
||||||
|
// is thrown.
|
||||||
|
if b.llvmFn.Linkage() != llvm.InternalLinkage &&
|
||||||
|
b.llvmFn.Linkage() != llvm.PrivateLinkage {
|
||||||
|
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
||||||
|
}
|
||||||
b.llvmFn.SetUnnamedAddr(true)
|
b.llvmFn.SetUnnamedAddr(true)
|
||||||
}
|
}
|
||||||
if b.info.section != "" {
|
if b.info.section != "" {
|
||||||
@@ -1265,6 +1273,7 @@ func (b *builder) createFunction() {
|
|||||||
// Create anonymous functions (closures etc.).
|
// Create anonymous functions (closures etc.).
|
||||||
for _, sub := range b.fn.AnonFuncs {
|
for _, sub := range b.fn.AnonFuncs {
|
||||||
b := newBuilder(b.compilerContext, b.Builder, sub)
|
b := newBuilder(b.compilerContext, b.Builder, sub)
|
||||||
|
b.llvmFn.SetLinkage(llvm.InternalLinkage)
|
||||||
b.createFunction()
|
b.createFunction()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -196,7 +196,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #1 {
|
define internal void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -115,7 +115,7 @@ declare i8* @llvm.stacksave() #2
|
|||||||
declare void @runtime.setupDeferFrame(%runtime.deferFrame* dereferenceable_or_null(24), i8*, i8*) #0
|
declare void @runtime.setupDeferFrame(%runtime.deferFrame* dereferenceable_or_null(24), i8*, i8*) #0
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @"main.deferSimple$1"(i8* %context) unnamed_addr #1 {
|
define internal void @"main.deferSimple$1"(i8* %context) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.printint32(i32 3, i8* undef) #3
|
call void @runtime.printint32(i32 3, i8* undef) #3
|
||||||
ret void
|
ret void
|
||||||
@@ -246,14 +246,14 @@ rundefers.end9: ; preds = %rundefers.loophead1
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @"main.deferMultiple$1"(i8* %context) unnamed_addr #1 {
|
define internal void @"main.deferMultiple$1"(i8* %context) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.printint32(i32 3, i8* undef) #3
|
call void @runtime.printint32(i32 3, i8* undef) #3
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @"main.deferMultiple$2"(i8* %context) unnamed_addr #1 {
|
define internal void @"main.deferMultiple$2"(i8* %context) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
call void @runtime.printint32(i32 5, i8* undef) #3
|
call void @runtime.printint32(i32 5, i8* undef) #3
|
||||||
ret void
|
ret void
|
||||||
|
|||||||
+2
-2
@@ -51,7 +51,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
%unpack.ptr = bitcast i8* %context to i32*
|
%unpack.ptr = bitcast i8* %context to i32*
|
||||||
store i32 7, i32* %unpack.ptr, align 4
|
store i32 7, i32* %unpack.ptr, align 4
|
||||||
|
|||||||
+2
-2
@@ -53,7 +53,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ entry:
|
|||||||
}
|
}
|
||||||
|
|
||||||
; Function Attrs: nounwind
|
; Function Attrs: nounwind
|
||||||
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
define internal void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
|
||||||
entry:
|
entry:
|
||||||
%unpack.ptr = bitcast i8* %context to i32*
|
%unpack.ptr = bitcast i8* %context to i32*
|
||||||
store i32 7, i32* %unpack.ptr, align 4
|
store i32 7, i32* %unpack.ptr, align 4
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
// Version of TinyGo.
|
// Version of TinyGo.
|
||||||
// Update this value before release of new version of software.
|
// Update this value before release of new version of software.
|
||||||
const Version = "0.25.0-dev"
|
const Version = "0.25.0"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// This variable is set at build time using -ldflags parameters.
|
// This variable is set at build time using -ldflags parameters.
|
||||||
|
|||||||
@@ -99,9 +99,9 @@ func Pause() {
|
|||||||
//export tinygo_unwind
|
//export tinygo_unwind
|
||||||
func (*stackState) unwind()
|
func (*stackState) unwind()
|
||||||
|
|
||||||
// Switch to this task until it pauses or completes.
|
// Resume the task until it pauses or completes.
|
||||||
// This may only be called from the scheduler.
|
// This may only be called from the scheduler.
|
||||||
func (t *Task) Switch() {
|
func (t *Task) Resume() {
|
||||||
// The current task must be saved and restored because this can nest on WASM with JS.
|
// The current task must be saved and restored because this can nest on WASM with JS.
|
||||||
prevTask := currentTask
|
prevTask := currentTask
|
||||||
t.gcData.swap()
|
t.gcData.swap()
|
||||||
@@ -121,3 +121,9 @@ func (t *Task) Switch() {
|
|||||||
|
|
||||||
//export tinygo_rewind
|
//export tinygo_rewind
|
||||||
func (*state) rewind()
|
func (*state) rewind()
|
||||||
|
|
||||||
|
// OnSystemStack returns whether the caller is running on the system stack.
|
||||||
|
func OnSystemStack() bool {
|
||||||
|
// If there is not an active goroutine, then this must be running on the system stack.
|
||||||
|
return Current() == nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,12 +28,12 @@ func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
|||||||
|
|
||||||
type state struct{}
|
type state struct{}
|
||||||
|
|
||||||
func (t *Task) Switch() {
|
func (t *Task) Resume() {
|
||||||
runtimePanic("scheduler is disabled")
|
runtimePanic("scheduler is disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
// MainTask returns whether the caller is running in the main goroutine.
|
// OnSystemStack returns whether the caller is running on the system stack.
|
||||||
func MainTask() bool {
|
func OnSystemStack() bool {
|
||||||
// This scheduler does not do any stack switching.
|
// This scheduler does not do any stack switching.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,12 +27,8 @@ type state struct {
|
|||||||
canaryPtr *uintptr
|
canaryPtr *uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
// The task struct for the main goroutine.
|
// currentTask is the current running task, or nil if currently in the scheduler.
|
||||||
var mainTask Task
|
var currentTask *Task
|
||||||
|
|
||||||
// currentTask is the current running task. The default value is the main
|
|
||||||
// goroutine.
|
|
||||||
var currentTask = &mainTask
|
|
||||||
|
|
||||||
// Current returns the current active task.
|
// Current returns the current active task.
|
||||||
func Current() *Task {
|
func Current() *Task {
|
||||||
@@ -40,36 +36,29 @@ func Current() *Task {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pause suspends the current task and returns to the scheduler.
|
// Pause suspends the current task and returns to the scheduler.
|
||||||
// This function may only be called when running on a goroutine stack, not when in an interrupt.
|
// This function may only be called when running on a goroutine stack, not when running on the system stack or in an interrupt.
|
||||||
func Pause() {
|
func Pause() {
|
||||||
// Check whether the canary (the lowest address of the stack) is still
|
// Check whether the canary (the lowest address of the stack) is still
|
||||||
// valid. If it is not, a stack overflow has occured.
|
// valid. If it is not, a stack overflow has occured.
|
||||||
if currentTask.state.canaryPtr != nil && *currentTask.state.canaryPtr != stackCanary {
|
if *currentTask.state.canaryPtr != stackCanary {
|
||||||
runtimePanic("goroutine stack overflow")
|
runtimePanic("goroutine stack overflow")
|
||||||
}
|
}
|
||||||
scheduler()
|
currentTask.state.pause()
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname scheduler runtime.scheduler
|
|
||||||
func scheduler()
|
|
||||||
|
|
||||||
//export tinygo_pause
|
//export tinygo_pause
|
||||||
func pause() {
|
func pause() {
|
||||||
Pause()
|
Pause()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Switch to the given task until it pauses or completes.
|
// Resume the task until it pauses or completes.
|
||||||
// This may only be called from the scheduler.
|
// This may only be called from the scheduler.
|
||||||
func (t *Task) Switch() {
|
func (t *Task) Resume() {
|
||||||
current := currentTask
|
|
||||||
if current == t {
|
|
||||||
// Nothing to switch to: we're already in this task.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
currentTask = t
|
currentTask = t
|
||||||
t.gcData.swap()
|
t.gcData.swap()
|
||||||
t.state.switchTo(current)
|
t.state.resume()
|
||||||
t.gcData.swap()
|
t.gcData.swap()
|
||||||
|
currentTask = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the state and prepare to call the specified function with the specified argument bundle.
|
// initialize the state and prepare to call the specified function with the specified argument bundle.
|
||||||
@@ -114,8 +103,8 @@ func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
|||||||
runqueuePushBack(t)
|
runqueuePushBack(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MainTask returns whether the caller is running in the main goroutine.
|
// OnSystemStack returns whether the caller is running on the system stack.
|
||||||
func MainTask() bool {
|
func OnSystemStack() bool {
|
||||||
// If there is not an active goroutine, then this must be running on the system stack.
|
// If there is not an active goroutine, then this must be running on the system stack.
|
||||||
return currentTask == &mainTask
|
return Current() == nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,11 @@ tinygo_startTask:
|
|||||||
// Branch to the "goroutine start" function.
|
// Branch to the "goroutine start" function.
|
||||||
calll *%ebx
|
calll *%ebx
|
||||||
|
|
||||||
// After return, exit this goroutine.
|
// Rebalance the stack (to undo the above push).
|
||||||
calll tinygo_pause
|
addl $4, %esp
|
||||||
|
|
||||||
|
// After return, exit this goroutine. This is a tail call.
|
||||||
|
jmp tinygo_pause
|
||||||
.cfi_endproc
|
.cfi_endproc
|
||||||
|
|
||||||
.global tinygo_swapTask
|
.global tinygo_swapTask
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ package task
|
|||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
|
var systemStack uintptr
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||||
// switching between tasks. Also see task_stack_386.S that relies on the exact
|
// switching between tasks. Also see task_stack_386.S that relies on the exact
|
||||||
// layout of this struct.
|
// layout of this struct.
|
||||||
@@ -44,12 +46,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|||||||
r.esi = uintptr(args)
|
r.esi = uintptr(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) switchTo(current *Task) {
|
func (s *state) resume() {
|
||||||
swapTask(s.sp, ¤t.state.sp)
|
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.
|
// SystemStack returns the system stack pointer when called from a task stack.
|
||||||
// When called from the system stack, it returns 0.
|
// When called from the system stack, it returns 0.
|
||||||
func SystemStack() uintptr {
|
func SystemStack() uintptr {
|
||||||
return mainTask.state.sp
|
return systemStack
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,11 +28,11 @@ tinygo_startTask:
|
|||||||
// Branch to the "goroutine start" function.
|
// Branch to the "goroutine start" function.
|
||||||
callq *%r12
|
callq *%r12
|
||||||
|
|
||||||
// After return, exit this goroutine.
|
// After return, exit this goroutine. This is a tail call.
|
||||||
#ifdef __MACH__
|
#ifdef __MACH__
|
||||||
callq _tinygo_pause
|
jmp _tinygo_pause
|
||||||
#else
|
#else
|
||||||
callq tinygo_pause
|
jmp tinygo_pause
|
||||||
#endif
|
#endif
|
||||||
.cfi_endproc
|
.cfi_endproc
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ package task
|
|||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
|
var systemStack uintptr
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||||
// switching between tasks. Also see task_stack_amd64.S that relies on the exact
|
// switching between tasks. Also see task_stack_amd64.S that relies on the exact
|
||||||
// layout of this struct.
|
// layout of this struct.
|
||||||
@@ -43,12 +45,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|||||||
r.r13 = uintptr(args)
|
r.r13 = uintptr(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) switchTo(current *Task) {
|
func (s *state) resume() {
|
||||||
swapTask(s.sp, ¤t.state.sp)
|
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.
|
// SystemStack returns the system stack pointer when called from a task stack.
|
||||||
// When called from the system stack, it returns 0.
|
// When called from the system stack, it returns 0.
|
||||||
func SystemStack() uintptr {
|
func SystemStack() uintptr {
|
||||||
return mainTask.state.sp
|
return systemStack
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ tinygo_startTask:
|
|||||||
// Branch to the "goroutine start" function.
|
// Branch to the "goroutine start" function.
|
||||||
callq *%r12
|
callq *%r12
|
||||||
|
|
||||||
// After return, exit this goroutine.
|
// After return, exit this goroutine. This is a tail call.
|
||||||
callq tinygo_pause
|
jmp tinygo_pause
|
||||||
|
|
||||||
.global tinygo_swapTask
|
.global tinygo_swapTask
|
||||||
.section .text.tinygo_swapTask,"ax"
|
.section .text.tinygo_swapTask,"ax"
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ package task
|
|||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
|
var systemStack uintptr
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||||
// switching between tasks. Also see task_stack_amd64_windows.S that relies on
|
// switching between tasks. Also see task_stack_amd64_windows.S that relies on
|
||||||
// the exact layout of this struct.
|
// the exact layout of this struct.
|
||||||
@@ -48,12 +50,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|||||||
r.r13 = uintptr(args)
|
r.r13 = uintptr(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) switchTo(current *Task) {
|
func (s *state) resume() {
|
||||||
swapTask(s.sp, ¤t.state.sp)
|
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.
|
// SystemStack returns the system stack pointer when called from a task stack.
|
||||||
// When called from the system stack, it returns 0.
|
// When called from the system stack, it returns 0.
|
||||||
func SystemStack() uintptr {
|
func SystemStack() uintptr {
|
||||||
return mainTask.state.sp
|
return systemStack
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ package task
|
|||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
|
var systemStack uintptr
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||||
// switching between tasks. Also see task_stack_arm.S that relies on the exact
|
// switching between tasks. Also see task_stack_arm.S that relies on the exact
|
||||||
// layout of this struct.
|
// layout of this struct.
|
||||||
@@ -43,12 +45,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|||||||
r.r5 = uintptr(args)
|
r.r5 = uintptr(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) switchTo(current *Task) {
|
func (s *state) resume() {
|
||||||
swapTask(s.sp, ¤t.state.sp)
|
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.
|
// SystemStack returns the system stack pointer when called from a task stack.
|
||||||
// When called from the system stack, it returns 0.
|
// When called from the system stack, it returns 0.
|
||||||
func SystemStack() uintptr {
|
func SystemStack() uintptr {
|
||||||
return mainTask.state.sp
|
return systemStack
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ package task
|
|||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
|
var systemStack uintptr
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||||
// switching between tasks. Also see task_stack_arm64.S that relies on the exact
|
// switching between tasks. Also see task_stack_arm64.S that relies on the exact
|
||||||
// layout of this struct.
|
// layout of this struct.
|
||||||
@@ -46,12 +48,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|||||||
r.x20 = uintptr(args)
|
r.x20 = uintptr(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) switchTo(current *Task) {
|
func (s *state) resume() {
|
||||||
swapTask(s.sp, ¤t.state.sp)
|
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.
|
// SystemStack returns the system stack pointer when called from a task stack.
|
||||||
// When called from the system stack, it returns 0.
|
// When called from the system stack, it returns 0.
|
||||||
func SystemStack() uintptr {
|
func SystemStack() uintptr {
|
||||||
return mainTask.state.sp
|
return systemStack
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
.section .bss.tinygo_systemStack
|
||||||
|
.global tinygo_systemStack
|
||||||
|
.type tinygo_systemStack, %object
|
||||||
|
tinygo_systemStack:
|
||||||
|
.short 0
|
||||||
|
|
||||||
.section .text.tinygo_startTask
|
.section .text.tinygo_startTask
|
||||||
.global tinygo_startTask
|
.global tinygo_startTask
|
||||||
.type tinygo_startTask, %function
|
.type tinygo_startTask, %function
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ package task
|
|||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
|
//go:extern tinygo_systemStack
|
||||||
|
var systemStack uintptr
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||||
// switching between tasks. Also see task_stack_avr.S that relies on the exact
|
// switching between tasks. Also see task_stack_avr.S that relies on the exact
|
||||||
// layout of this struct.
|
// layout of this struct.
|
||||||
@@ -48,12 +51,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|||||||
r.r4r5 = uintptr(args)
|
r.r4r5 = uintptr(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) switchTo(current *Task) {
|
func (s *state) resume() {
|
||||||
swapTask(s.sp, ¤t.state.sp)
|
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.
|
// SystemStack returns the system stack pointer when called from a task stack.
|
||||||
// When called from the system stack, it returns 0.
|
// When called from the system stack, it returns 0.
|
||||||
func SystemStack() uintptr {
|
func SystemStack() uintptr {
|
||||||
return mainTask.state.sp
|
return systemStack
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
//go:build scheduler.tasks && baremetal
|
|
||||||
// +build scheduler.tasks,baremetal
|
|
||||||
|
|
||||||
package task
|
|
||||||
|
|
||||||
//go:extern _stack_bottom
|
|
||||||
var _stack_bottom uintptr
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
mainTask.state.canaryPtr = &_stack_bottom
|
|
||||||
*mainTask.state.canaryPtr = stackCanary
|
|
||||||
}
|
|
||||||
@@ -30,10 +30,10 @@ tinygo_startTask:
|
|||||||
.cfi_endproc
|
.cfi_endproc
|
||||||
.size tinygo_startTask, .-tinygo_startTask
|
.size tinygo_startTask, .-tinygo_startTask
|
||||||
|
|
||||||
.section .text.tinygo_switchToMain
|
.section .text.tinygo_switchToScheduler
|
||||||
.global tinygo_switchToMain
|
.global tinygo_switchToScheduler
|
||||||
.type tinygo_switchToMain, %function
|
.type tinygo_switchToScheduler, %function
|
||||||
tinygo_switchToMain:
|
tinygo_switchToScheduler:
|
||||||
.cfi_startproc
|
.cfi_startproc
|
||||||
// r0 = sp *uintptr
|
// r0 = sp *uintptr
|
||||||
|
|
||||||
@@ -43,9 +43,9 @@ tinygo_switchToMain:
|
|||||||
subs r1, #36
|
subs r1, #36
|
||||||
str r1, [r0]
|
str r1, [r0]
|
||||||
|
|
||||||
b tinygo_swapTaskInternal
|
b tinygo_swapTask
|
||||||
.cfi_endproc
|
.cfi_endproc
|
||||||
.size tinygo_switchToMain, .-tinygo_switchToMain
|
.size tinygo_switchToScheduler, .-tinygo_switchToScheduler
|
||||||
|
|
||||||
.section .text.tinygo_switchToTask
|
.section .text.tinygo_switchToTask
|
||||||
.global tinygo_switchToTask
|
.global tinygo_switchToTask
|
||||||
@@ -55,17 +55,17 @@ tinygo_switchToTask:
|
|||||||
// r0 = sp uintptr
|
// r0 = sp uintptr
|
||||||
|
|
||||||
// Currently on the scheduler stack (SP=MSP). We'll have to update the PSP,
|
// Currently on the scheduler stack (SP=MSP). We'll have to update the PSP,
|
||||||
// and then we can invoke swapTaskInternal.
|
// and then we can invoke swapTask.
|
||||||
msr PSP, r0
|
msr PSP, r0
|
||||||
|
|
||||||
b.n tinygo_swapTaskInternal
|
b.n tinygo_swapTask
|
||||||
.cfi_endproc
|
.cfi_endproc
|
||||||
.size tinygo_switchToTask, .-tinygo_switchToTask
|
.size tinygo_switchToTask, .-tinygo_switchToTask
|
||||||
|
|
||||||
.section .text.tinygo_swapTaskInternal
|
.section .text.tinygo_swapTask
|
||||||
.global tinygo_swapTaskInternal
|
.global tinygo_swapTask
|
||||||
.type tinygo_swapTaskInternal, %function
|
.type tinygo_swapTask, %function
|
||||||
tinygo_swapTaskInternal:
|
tinygo_swapTask:
|
||||||
.cfi_startproc
|
.cfi_startproc
|
||||||
// This function stores the current register state to the stack, switches to
|
// This function stores the current register state to the stack, switches to
|
||||||
// the other stack (MSP/PSP), and loads the register state from the other
|
// the other stack (MSP/PSP), and loads the register state from the other
|
||||||
@@ -77,15 +77,15 @@ tinygo_swapTaskInternal:
|
|||||||
// used directly. Only very few operations work on them, such as mov. That's
|
// used directly. Only very few operations work on them, such as mov. That's
|
||||||
// why the higher register values are first stored in the temporary register
|
// why the higher register values are first stored in the temporary register
|
||||||
// r3 when loading/storing them.
|
// r3 when loading/storing them.
|
||||||
// It is possible to reduce the swapTaskInternal by two instructions (~2
|
// It is possible to reduce the swapTask by two instructions (~2 cycles) on
|
||||||
// cycles) on Cortex-M0 by reordering the layout of the pushed registers
|
// Cortex-M0 by reordering the layout of the pushed registers from {r4-r11,
|
||||||
// from {r4-r11, lr} to {r8-r11, r4-r8, lr}. However, that also requires a
|
// lr} to {r8-r11, r4-r8, lr}. However, that also requires a change on the
|
||||||
// change on the Go side (depending on thumb1/thumb2!) and so is not really
|
// Go side (depending on thumb1/thumb2!) and so is not really worth the
|
||||||
// worth the complexity.
|
// complexity.
|
||||||
|
|
||||||
// Store state to old task. It saves the lr instead of the pc, because that
|
// Store state to old task. It saves the lr instead of the pc, because that
|
||||||
// will be the pc after returning back to the old task (in a different
|
// will be the pc after returning back to the old task (in a different
|
||||||
// invocation of swapTaskInternal).
|
// invocation of swapTask).
|
||||||
#if defined(__thumb2__)
|
#if defined(__thumb2__)
|
||||||
push {r4-r11, lr}
|
push {r4-r11, lr}
|
||||||
.cfi_def_cfa_offset 9*4
|
.cfi_def_cfa_offset 9*4
|
||||||
@@ -108,63 +108,6 @@ tinygo_swapTaskInternal:
|
|||||||
msr CONTROL, r0 // store CONTROL register
|
msr CONTROL, r0 // store CONTROL register
|
||||||
isb // required to flush the pipeline
|
isb // required to flush the pipeline
|
||||||
|
|
||||||
// Load state from new task and branch to the previous position in the
|
|
||||||
// program.
|
|
||||||
#if defined(__thumb2__)
|
|
||||||
pop {r4-r11, pc}
|
|
||||||
#else
|
|
||||||
pop {r4-r7}
|
|
||||||
.cfi_def_cfa_offset 5*9
|
|
||||||
pop {r0-r3}
|
|
||||||
.cfi_def_cfa_offset 1*9
|
|
||||||
mov r8, r0
|
|
||||||
mov r9, r1
|
|
||||||
mov r10, r2
|
|
||||||
mov r11, r3
|
|
||||||
pop {pc}
|
|
||||||
#endif
|
|
||||||
.cfi_endproc
|
|
||||||
.size tinygo_swapTaskInternal, .-tinygo_swapTaskInternal
|
|
||||||
|
|
||||||
|
|
||||||
.section .text.tinygo_swapTask
|
|
||||||
.global tinygo_swapTask
|
|
||||||
.type tinygo_swapTask, %function
|
|
||||||
tinygo_swapTask:
|
|
||||||
.cfi_startproc
|
|
||||||
// This function is like tinygo_swapTaskInternal but only switches the stack
|
|
||||||
// pointer without touching the SPSEL bit (to switch between MSP and PSP).
|
|
||||||
// Therefore, it is used to switch between two tasks that are not the main
|
|
||||||
// goroutine.
|
|
||||||
|
|
||||||
// Store state to old task. It saves the lr instead of the pc, because that
|
|
||||||
// will be the pc after returning back to the old task (in a different
|
|
||||||
// invocation of swapTask).
|
|
||||||
#if defined(__thumb2__)
|
|
||||||
push {r4-r11, lr}
|
|
||||||
.cfi_def_cfa_offset 9*4
|
|
||||||
#else
|
|
||||||
mov r0, r8
|
|
||||||
mov r1, r9
|
|
||||||
mov r2, r10
|
|
||||||
mov r3, r11
|
|
||||||
push {r0-r3, lr}
|
|
||||||
.cfi_def_cfa_offset 5*4
|
|
||||||
push {r4-r7}
|
|
||||||
.cfi_def_cfa_offset 9*4
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Save the current stack pointer in oldStack.
|
|
||||||
#if defined(__thumb2__)
|
|
||||||
str sp, [r1]
|
|
||||||
#else
|
|
||||||
mov r2, sp
|
|
||||||
str r2, [r1]
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Switch to the new stack pointer.
|
|
||||||
mov sp, r0
|
|
||||||
|
|
||||||
// Load state from new task and branch to the previous position in the
|
// Load state from new task and branch to the previous position in the
|
||||||
// program.
|
// program.
|
||||||
#if defined(__thumb2__)
|
#if defined(__thumb2__)
|
||||||
|
|||||||
@@ -52,23 +52,19 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|||||||
r.r5 = uintptr(args)
|
r.r5 = uintptr(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) switchTo(current *Task) {
|
func (s *state) resume() {
|
||||||
// This code is probably more complex than it needs to be.
|
switchToTask(s.sp)
|
||||||
// TODO: simplify this, ideally to a single function call.
|
|
||||||
if s == &mainTask.state {
|
|
||||||
switchToMain(¤t.state.sp)
|
|
||||||
} else if current == &mainTask {
|
|
||||||
switchToTask(s.sp)
|
|
||||||
} else {
|
|
||||||
swapTask(s.sp, ¤t.state.sp)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//export tinygo_switchToTask
|
//export tinygo_switchToTask
|
||||||
func switchToTask(uintptr)
|
func switchToTask(uintptr)
|
||||||
|
|
||||||
//export tinygo_switchToMain
|
//export tinygo_switchToScheduler
|
||||||
func switchToMain(*uintptr)
|
func switchToScheduler(*uintptr)
|
||||||
|
|
||||||
|
func (s *state) pause() {
|
||||||
|
switchToScheduler(&s.sp)
|
||||||
|
}
|
||||||
|
|
||||||
// SystemStack returns the system stack pointer. On Cortex-M, it is always
|
// SystemStack returns the system stack pointer. On Cortex-M, it is always
|
||||||
// available.
|
// available.
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var systemStack uintptr
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||||
// switching between tasks. Also see task_stack_esp8266.S that relies on the
|
// switching between tasks. Also see task_stack_esp8266.S that relies on the
|
||||||
// exact layout of this struct.
|
// exact layout of this struct.
|
||||||
@@ -58,12 +60,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|||||||
r.a2 = uintptr(args)
|
r.a2 = uintptr(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) switchTo(current *Task) {
|
func (s *state) resume() {
|
||||||
swapTask(s.sp, ¤t.state.sp)
|
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.
|
// SystemStack returns the system stack pointer when called from a task stack.
|
||||||
// When called from the system stack, it returns 0.
|
// When called from the system stack, it returns 0.
|
||||||
func SystemStack() uintptr {
|
func SystemStack() uintptr {
|
||||||
return mainTask.state.sp
|
return systemStack
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ package task
|
|||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
|
var systemStack uintptr
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||||
// switching between tasks. Also see task_stack_esp8266.S that relies on the
|
// switching between tasks. Also see task_stack_esp8266.S that relies on the
|
||||||
// exact layout of this struct.
|
// exact layout of this struct.
|
||||||
@@ -52,12 +54,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|||||||
r.a13 = uintptr(args)
|
r.a13 = uintptr(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) switchTo(current *Task) {
|
func (s *state) resume() {
|
||||||
swapTask(s.sp, ¤t.state.sp)
|
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.
|
// SystemStack returns the system stack pointer when called from a task stack.
|
||||||
// When called from the system stack, it returns 0.
|
// When called from the system stack, it returns 0.
|
||||||
func SystemStack() uintptr {
|
func SystemStack() uintptr {
|
||||||
return mainTask.state.sp
|
return systemStack
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ package task
|
|||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
|
var systemStack uintptr
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
// 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
|
// switching between tasks. Also see scheduler_riscv.S that relies on the
|
||||||
// exact layout of this struct.
|
// exact layout of this struct.
|
||||||
@@ -48,12 +50,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|||||||
r.s1 = uintptr(args)
|
r.s1 = uintptr(args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) switchTo(current *Task) {
|
func (s *state) resume() {
|
||||||
swapTask(s.sp, ¤t.state.sp)
|
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.
|
// SystemStack returns the system stack pointer when called from a task stack.
|
||||||
// When called from the system stack, it returns 0.
|
// When called from the system stack, it returns 0.
|
||||||
func SystemStack() uintptr {
|
func SystemStack() uintptr {
|
||||||
return mainTask.state.sp
|
return systemStack
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ func markStack() {
|
|||||||
// Scan the current stack, and all current registers.
|
// Scan the current stack, and all current registers.
|
||||||
scanCurrentStack()
|
scanCurrentStack()
|
||||||
|
|
||||||
if !task.MainTask() {
|
if !task.OnSystemStack() {
|
||||||
// Mark system stack.
|
// Mark system stack.
|
||||||
markRoots(getSystemStackPointer(), stackTop)
|
markRoots(getSystemStackPointer(), stackTop)
|
||||||
}
|
}
|
||||||
@@ -28,7 +28,7 @@ func scanstack(sp uintptr) {
|
|||||||
// Mark current stack.
|
// Mark current stack.
|
||||||
// This function is called by scanCurrentStack, after pushing all registers onto the stack.
|
// This function is called by scanCurrentStack, after pushing all registers onto the stack.
|
||||||
// Callee-saved registers have been pushed onto stack by tinygo_localscan, so this will scan them too.
|
// Callee-saved registers have been pushed onto stack by tinygo_localscan, so this will scan them too.
|
||||||
if task.MainTask() {
|
if task.OnSystemStack() {
|
||||||
// This is the system stack.
|
// This is the system stack.
|
||||||
// Scan all words on the stack.
|
// Scan all words on the stack.
|
||||||
markRoots(sp, stackTop)
|
markRoots(sp, stackTop)
|
||||||
|
|||||||
@@ -49,6 +49,16 @@ func putchar(c byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getchar() byte {
|
||||||
|
// dummy, TODO
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func buffered() int {
|
||||||
|
// dummy, TODO
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
//go:linkname now time.now
|
//go:linkname now time.now
|
||||||
func now() (sec int64, nsec int32, mono int64) {
|
func now() (sec int64, nsec int32, mono int64) {
|
||||||
mono = nanotime()
|
mono = nanotime()
|
||||||
|
|||||||
@@ -112,7 +112,9 @@ func addSleepTask(t *task.Task, duration timeUnit) {
|
|||||||
*q = t
|
*q = t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run the scheduler until all tasks have finished.
|
||||||
func scheduler() {
|
func scheduler() {
|
||||||
|
// Main scheduler loop.
|
||||||
var now timeUnit
|
var now timeUnit
|
||||||
for !schedulerDone {
|
for !schedulerDone {
|
||||||
scheduleLog("")
|
scheduleLog("")
|
||||||
@@ -162,11 +164,7 @@ func scheduler() {
|
|||||||
|
|
||||||
// Run the given task.
|
// Run the given task.
|
||||||
scheduleLogTask(" run:", t)
|
scheduleLogTask(" run:", t)
|
||||||
t.Switch()
|
t.Resume()
|
||||||
if GOARCH != "wasm" {
|
|
||||||
// Don't return when using Asyncify.
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +181,7 @@ func minSched() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
scheduleLogTask(" run:", t)
|
scheduleLogTask(" run:", t)
|
||||||
t.Switch()
|
t.Resume()
|
||||||
}
|
}
|
||||||
scheduleLog("stop nested scheduler")
|
scheduleLog("stop nested scheduler")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
//go:build scheduler.asyncify
|
//go:build !scheduler.none
|
||||||
// +build scheduler.asyncify
|
// +build !scheduler.none
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
@@ -16,27 +16,3 @@ func getSystemStackPointer() uintptr {
|
|||||||
}
|
}
|
||||||
return sp
|
return sp
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pause the current task for a given time.
|
|
||||||
//
|
|
||||||
//go:linkname sleep time.Sleep
|
|
||||||
func sleep(duration int64) {
|
|
||||||
if duration <= 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
addSleepTask(task.Current(), nanosecondsToTicks(duration))
|
|
||||||
task.Pause()
|
|
||||||
}
|
|
||||||
|
|
||||||
// run is called by the program entry point to execute the go program.
|
|
||||||
// The main goroutine runs on the system stack, so initAll and callMain can be
|
|
||||||
// called directly.
|
|
||||||
func run() {
|
|
||||||
initHeap()
|
|
||||||
initAll()
|
|
||||||
callMain()
|
|
||||||
schedulerDone = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasScheduler = true
|
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ SECTIONS
|
|||||||
.stack (NOLOAD) :
|
.stack (NOLOAD) :
|
||||||
{
|
{
|
||||||
. = ALIGN(4);
|
. = ALIGN(4);
|
||||||
_stack_bottom = .;
|
|
||||||
. += _stack_size;
|
. += _stack_size;
|
||||||
_stack_top = .;
|
_stack_top = .;
|
||||||
} >RAM
|
} >RAM
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ SECTIONS
|
|||||||
|
|
||||||
.stack (NOLOAD) :
|
.stack (NOLOAD) :
|
||||||
{
|
{
|
||||||
_stack_bottom = .;
|
|
||||||
. += _stack_size;
|
. += _stack_size;
|
||||||
_stack_top = .;
|
_stack_top = .;
|
||||||
} >RAM
|
} >RAM
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ SECTIONS
|
|||||||
.stack (NOLOAD) :
|
.stack (NOLOAD) :
|
||||||
{
|
{
|
||||||
. = ALIGN(16);
|
. = ALIGN(16);
|
||||||
_stack_bottom = .;
|
|
||||||
. += _stack_size;
|
. += _stack_size;
|
||||||
_stack_top = .;
|
_stack_top = .;
|
||||||
} >DRAM
|
} >DRAM
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ SECTIONS
|
|||||||
.stack (NOLOAD) :
|
.stack (NOLOAD) :
|
||||||
{
|
{
|
||||||
. = ALIGN(16);
|
. = ALIGN(16);
|
||||||
_stack_bottom = .;
|
|
||||||
. += _stack_size;
|
. += _stack_size;
|
||||||
_stack_top = .;
|
_stack_top = .;
|
||||||
} >DRAM
|
} >DRAM
|
||||||
|
|||||||
@@ -67,11 +67,6 @@ _heap_end = ORIGIN(DRAM) + LENGTH(DRAM);
|
|||||||
*/
|
*/
|
||||||
_stack_top = 0x40000000;
|
_stack_top = 0x40000000;
|
||||||
|
|
||||||
/* This is the stack bottom according to this forum post:
|
|
||||||
* https://bbs.espressif.com/viewtopic.php?t=8879#p19038
|
|
||||||
*/
|
|
||||||
_stack_bottom = 0x3fffeb2c;
|
|
||||||
|
|
||||||
/* Functions normally provided by a libc.
|
/* Functions normally provided by a libc.
|
||||||
* Source:
|
* Source:
|
||||||
* https://github.com/espressif/ESP8266_NONOS_SDK/blob/master/ld/eagle.rom.addr.v6.ld
|
* https://github.com/espressif/ESP8266_NONOS_SDK/blob/master/ld/eagle.rom.addr.v6.ld
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ SECTIONS
|
|||||||
}
|
}
|
||||||
|
|
||||||
PROVIDE(_stack_top = ORIGIN(RAM) + LENGTH(RAM));
|
PROVIDE(_stack_top = ORIGIN(RAM) + LENGTH(RAM));
|
||||||
_stack_bottom = _stack_top - _stack_size;
|
|
||||||
|
|
||||||
/* For the memory allocator. */
|
/* For the memory allocator. */
|
||||||
_heap_start = _ebss;
|
_heap_start = _ebss;
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ SECTIONS
|
|||||||
.stack (NOLOAD) : {
|
.stack (NOLOAD) : {
|
||||||
|
|
||||||
. = ALIGN(8);
|
. = ALIGN(8);
|
||||||
_stack_bottom = .;
|
|
||||||
. += _stack_size;
|
. += _stack_size;
|
||||||
_stack_top = .;
|
_stack_top = .;
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ SECTIONS
|
|||||||
.stack (NOLOAD) :
|
.stack (NOLOAD) :
|
||||||
{
|
{
|
||||||
. = ALIGN(16);
|
. = ALIGN(16);
|
||||||
_stack_bottom = .;
|
|
||||||
. += _stack_size;
|
. += _stack_size;
|
||||||
_stack_top = .;
|
_stack_top = .;
|
||||||
} >RAM
|
} >RAM
|
||||||
|
|||||||
Vendored
+8
@@ -1,11 +1,19 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tinygo-org/tinygo/testdata/generics/testa"
|
||||||
|
"github.com/tinygo-org/tinygo/testdata/generics/testb"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
println("add:", Add(3, 5))
|
println("add:", Add(3, 5))
|
||||||
println("add:", Add(int8(3), 5))
|
println("add:", Add(int8(3), 5))
|
||||||
|
|
||||||
var c C[int]
|
var c C[int]
|
||||||
c.F() // issue 2951
|
c.F() // issue 2951
|
||||||
|
|
||||||
|
testa.Test()
|
||||||
|
testb.Test()
|
||||||
}
|
}
|
||||||
|
|
||||||
type Integer interface {
|
type Integer interface {
|
||||||
|
|||||||
Vendored
+4
@@ -1,2 +1,6 @@
|
|||||||
add: 8
|
add: 8
|
||||||
add: 8
|
add: 8
|
||||||
|
value: 101
|
||||||
|
value: 101
|
||||||
|
value: 501
|
||||||
|
value: 501
|
||||||
|
|||||||
Vendored
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package testa
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tinygo-org/tinygo/testdata/generics/value"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test() {
|
||||||
|
v := value.New(1)
|
||||||
|
vm := value.Map(v, Plus100)
|
||||||
|
vm.Get(callback, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
func callback(v int) {
|
||||||
|
println("value:", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plus100 is a `Transform` that adds 100 to `value`.
|
||||||
|
func Plus100(value int) int {
|
||||||
|
return value + 100
|
||||||
|
}
|
||||||
Vendored
+20
@@ -0,0 +1,20 @@
|
|||||||
|
package testb
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tinygo-org/tinygo/testdata/generics/value"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test() {
|
||||||
|
v := value.New(1)
|
||||||
|
vm := value.Map(v, Plus500)
|
||||||
|
vm.Get(callback, callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
func callback(v int) {
|
||||||
|
println("value:", v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plus500 is a `Transform` that adds 500 to `value`.
|
||||||
|
func Plus500(value int) int {
|
||||||
|
return value + 500
|
||||||
|
}
|
||||||
Vendored
+53
@@ -0,0 +1,53 @@
|
|||||||
|
package value
|
||||||
|
|
||||||
|
type (
|
||||||
|
Value[T any] interface {
|
||||||
|
Get(Callback[T], Callback[T])
|
||||||
|
}
|
||||||
|
|
||||||
|
Callback[T any] func(T)
|
||||||
|
|
||||||
|
Transform[S any, D any] func(S) D
|
||||||
|
)
|
||||||
|
|
||||||
|
func New[T any](v T) Value[T] {
|
||||||
|
return &value[T]{
|
||||||
|
v: v,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type value[T any] struct {
|
||||||
|
v T
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *value[T]) Get(fn1, fn2 Callback[T]) {
|
||||||
|
// For example purposes.
|
||||||
|
// Normally would be asynchronous callback.
|
||||||
|
fn1(v.v)
|
||||||
|
fn2(v.v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Map[S, D any](v Value[S], tx Transform[S, D]) Value[D] {
|
||||||
|
return &mapper[S, D]{
|
||||||
|
v: v,
|
||||||
|
tx: tx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type mapper[S, D any] struct {
|
||||||
|
v Value[S]
|
||||||
|
tx Transform[S, D]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *mapper[S, D]) Get(fn1, fn2 Callback[D]) {
|
||||||
|
// two callbacks are passed to generate more than
|
||||||
|
// one anonymous function symbol name.
|
||||||
|
m.v.Get(func(v S) {
|
||||||
|
// anonymous function inside of anonymous function.
|
||||||
|
func() {
|
||||||
|
fn1(m.tx(v))
|
||||||
|
}()
|
||||||
|
}, func(v S) {
|
||||||
|
fn2(m.tx(v))
|
||||||
|
})
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user