From 293f4ea7bc9858c219c75bd3c2bc88dea1d42b99 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 30 Mar 2021 13:41:29 +0200 Subject: [PATCH 01/29] compiler: add tests for pragmas These pragmas weren't really tested anywhere, except that some code might break if they are not properly applied. These tests make it easy to see they work correctly and also provide a logical place to add new pragma tests. I've also made a slight change to how functions and globals are created: with the change they're also created in the IR even if they're not referenced. This makes testing easier. --- compiler/compiler.go | 6 +++--- compiler/compiler_test.go | 1 + compiler/testdata/pragma.go | 41 +++++++++++++++++++++++++++++++++++ compiler/testdata/pragma.ll | 43 +++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 compiler/testdata/pragma.go create mode 100644 compiler/testdata/pragma.ll diff --git a/compiler/compiler.go b/compiler/compiler.go index 925b61bf8..a34d98483 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -715,11 +715,11 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package member := pkg.Members[name] switch member := member.(type) { case *ssa.Function: + // Create the function definition. + b := newBuilder(c, irbuilder, member) if member.Blocks == nil { continue // external function } - // Create the function definition. - b := newBuilder(c, irbuilder, member) b.createFunction() case *ssa.Type: if types.IsInterface(member.Type()) { @@ -758,8 +758,8 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package case *ssa.Global: // Global variable. info := c.getGlobalInfo(member) + global := c.getGlobal(member) if !info.extern { - global := c.getGlobal(member) global.SetInitializer(llvm.ConstNull(global.Type().ElementType())) global.SetVisibility(llvm.HiddenVisibility) } diff --git a/compiler/compiler_test.go b/compiler/compiler_test.go index 4149e1491..45d5b8c3a 100644 --- a/compiler/compiler_test.go +++ b/compiler/compiler_test.go @@ -45,6 +45,7 @@ func TestCompiler(t *testing.T) { {"float.go", ""}, {"interface.go", ""}, {"func.go", ""}, + {"pragma.go", ""}, {"goroutine.go", "wasm"}, {"goroutine.go", "cortex-m-qemu"}, } diff --git a/compiler/testdata/pragma.go b/compiler/testdata/pragma.go new file mode 100644 index 000000000..505e78a9f --- /dev/null +++ b/compiler/testdata/pragma.go @@ -0,0 +1,41 @@ +package main + +import _ "unsafe" + +// Creates an external global with name extern_global. +//go:extern extern_global +var externGlobal [0]byte + +// Creates a +//go:align 32 +var alignedGlobal [4]uint32 + +// Test conflicting pragmas (the last one counts). +//go:align 64 +//go:align 16 +var alignedGlobal16 [4]uint32 + +// Test exported functions. +//export extern_func +func externFunc() { +} + +// Define a function in a different package using go:linkname. +//go:linkname withLinkageName1 somepkg.someFunction1 +func withLinkageName1() { +} + +// Import a function from a different package using go:linkname. +//go:linkname withLinkageName2 somepkg.someFunction2 +func withLinkageName2() + +// Function has an 'inline hint', similar to the inline keyword in C. +//go:inline +func inlineFunc() { +} + +// Function should never be inlined, equivalent to GCC +// __attribute__((noinline)). +//go:noinline +func noinlineFunc() { +} diff --git a/compiler/testdata/pragma.ll b/compiler/testdata/pragma.ll new file mode 100644 index 000000000..0fdc753e5 --- /dev/null +++ b/compiler/testdata/pragma.ll @@ -0,0 +1,43 @@ +; ModuleID = 'pragma.go' +source_filename = "pragma.go" +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32--wasi" + +@extern_global = external global [0 x i8], align 1 +@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32 +@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16 + +declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) + +define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr { +entry: + ret void +} + +define void @extern_func() #0 { +entry: + ret void +} + +define hidden void @somepkg.someFunction1(i8* %context, i8* %parentHandle) unnamed_addr { +entry: + ret void +} + +declare void @somepkg.someFunction2(i8*, i8*) + +; Function Attrs: inlinehint +define hidden void @main.inlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #1 { +entry: + ret void +} + +; Function Attrs: noinline +define hidden void @main.noinlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #2 { +entry: + ret void +} + +attributes #0 = { "wasm-export-name"="extern_func" } +attributes #1 = { inlinehint } +attributes #2 = { noinline } From 2bb70812a8cc0562204622689652132938567a81 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 30 Mar 2021 14:09:23 +0200 Subject: [PATCH 02/29] compiler: add function and global section pragmas This patch adds a new pragma for functions and globals to set the section name. This can be useful to place a function or global in a special device specific section, for example: * Functions may be placed in RAM to make them run faster, or in flash (if RAM is the default) to not let them take up RAM. * DMA memory may only be placed in a special memory area. * Some RAM may be faster than other RAM, and some globals may be performance critical thus placing them in this special RAM area can help. * Some (large) global variables may need to be placed in external RAM, which can be done by placing them in a special section. To use it, you have to place a function or global in a special section, for example: //go:section .externalram var externalRAMBuffer [1024]byte This can then be placed in a special section of the linker script, for example something like this: .bss.extram (NOLOAD) : { *(.externalram) } > ERAM --- compiler/compiler.go | 6 ++++++ compiler/symbol.go | 10 ++++++++++ compiler/testdata/pragma.go | 25 +++++++++++++++++++++++++ compiler/testdata/pragma.ll | 16 ++++++++++++++++ transform/globals.go | 2 +- 5 files changed, 58 insertions(+), 1 deletion(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index a34d98483..cc696d5b0 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -762,6 +762,9 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package if !info.extern { global.SetInitializer(llvm.ConstNull(global.Type().ElementType())) global.SetVisibility(llvm.HiddenVisibility) + if info.section != "" { + global.SetSection(info.section) + } } } } @@ -787,6 +790,9 @@ func (b *builder) createFunction() { b.llvmFn.SetVisibility(llvm.HiddenVisibility) b.llvmFn.SetUnnamedAddr(true) } + if b.info.section != "" { + b.llvmFn.SetSection(b.info.section) + } if b.info.exported && strings.HasPrefix(b.Triple, "wasm") { // Set the exported name. This is necessary for WebAssembly because // otherwise the function is not exported. diff --git a/compiler/symbol.go b/compiler/symbol.go index 6eec892dd..49ccfa20d 100644 --- a/compiler/symbol.go +++ b/compiler/symbol.go @@ -24,6 +24,7 @@ type functionInfo struct { module string // go:wasm-module importName string // go:linkname, go:export - The name the developer assigns linkName string // go:linkname, go:export - The name that we map for the particular module -> importName + section string // go:section - object file section name exported bool // go:export, CGo nobounds bool // go:nobounds variadic bool // go:variadic (CGo only) @@ -270,6 +271,10 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) { if hasUnsafeImport(f.Pkg.Pkg) { info.linkName = parts[2] } + case "//go:section": + if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) { + info.section = parts[1] + } case "//go:nobounds": // Skip bounds checking in this function. Useful for some // runtime functions. @@ -325,6 +330,7 @@ type globalInfo struct { linkName string // go:extern extern bool // go:extern align int // go:align + section string // go:section } // loadASTComments loads comments on globals from the AST, for use later in the @@ -438,6 +444,10 @@ func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) { if err == nil { info.align = align } + case "//go:section": + if len(parts) == 2 { + info.section = parts[1] + } } } } diff --git a/compiler/testdata/pragma.go b/compiler/testdata/pragma.go index 505e78a9f..b6ebc83b2 100644 --- a/compiler/testdata/pragma.go +++ b/compiler/testdata/pragma.go @@ -39,3 +39,28 @@ func inlineFunc() { //go:noinline func noinlineFunc() { } + +// This function should have the specified section. +//go:section .special_function_section +func functionInSection() { +} + +//export exportedFunctionInSection +//go:section .special_function_section +func exportedFunctionInSection() { +} + +// This function should not: it's only a declaration and not a definition. +//go:section .special_function_section +func undefinedFunctionNotInSection() + +//go:section .special_global_section +var globalInSection uint32 + +//go:section .special_global_section +//go:extern undefinedGlobalNotInSection +var undefinedGlobalNotInSection uint32 + +//go:align 1024 +//go:section .global_section +var multipleGlobalPragmas uint32 diff --git a/compiler/testdata/pragma.ll b/compiler/testdata/pragma.ll index 0fdc753e5..0515098c5 100644 --- a/compiler/testdata/pragma.ll +++ b/compiler/testdata/pragma.ll @@ -6,6 +6,9 @@ target triple = "wasm32--wasi" @extern_global = external global [0 x i8], align 1 @main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32 @main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16 +@main.globalInSection = hidden global i32 0, section ".special_global_section", align 4 +@undefinedGlobalNotInSection = external global i32, align 4 +@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024 declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) @@ -38,6 +41,19 @@ entry: ret void } +define hidden void @main.functionInSection(i8* %context, i8* %parentHandle) unnamed_addr section ".special_function_section" { +entry: + ret void +} + +define void @exportedFunctionInSection() #3 section ".special_function_section" { +entry: + ret void +} + +declare void @main.undefinedFunctionNotInSection(i8*, i8*) + attributes #0 = { "wasm-export-name"="extern_func" } attributes #1 = { inlinehint } attributes #2 = { noinline } +attributes #3 = { "wasm-export-name"="exportedFunctionInSection" } diff --git a/transform/globals.go b/transform/globals.go index 2d0349e9f..d147062bf 100644 --- a/transform/globals.go +++ b/transform/globals.go @@ -11,7 +11,7 @@ import "tinygo.org/x/go-llvm" func ApplyFunctionSections(mod llvm.Module) { llvmFn := mod.FirstFunction() for !llvmFn.IsNil() { - if !llvmFn.IsDeclaration() { + if !llvmFn.IsDeclaration() && llvmFn.Section() == "" { name := llvmFn.Name() llvmFn.SetSection(".text." + name) } From bfe3f6864741da9259b27c6ba372ded4cbdaa562 Mon Sep 17 00:00:00 2001 From: Yurii Soldak Date: Mon, 14 Jun 2021 00:50:46 +0200 Subject: [PATCH 03/29] smoke&readme: add missing boards --- Makefile | 6 +++++- README.md | 8 ++++++-- targets/nano-33-ble-sense.json | 3 +++ 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 targets/nano-33-ble-sense.json diff --git a/Makefile b/Makefile index e2981789b..6abdc261d 100644 --- a/Makefile +++ b/Makefile @@ -356,7 +356,11 @@ smoketest: @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=arduino-nano33 examples/blinky1 @$(MD5SUM) test.hex - $(TINYGO) build -size short -o test.hex -target=pico examples/blinky1 + $(TINYGO) build -size short -o test.hex -target=pico examples/blinky1 + @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=nano-33-ble examples/blinky1 + @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=nano-rp2040 examples/blinky1 @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1 @$(MD5SUM) test.hex diff --git a/README.md b/README.md index ae3a8b526..f28f4eb8f 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for You can compile TinyGo programs for microcontrollers, WebAssembly and Linux. -The following 63 microcontroller boards are currently supported: +The following 67 microcontroller boards are currently supported: * [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333) * [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333) @@ -69,7 +69,10 @@ The following 63 microcontroller boards are currently supported: * [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3) * [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi) * [Arduino Nano](https://store.arduino.cc/arduino-nano) -* [Arduino Nano33 IoT](https://store.arduino.cc/nano-33-iot) +* [Arduino Nano 33 BLE](https://store.arduino.cc/nano-33-ble) +* [Arduino Nano 33 BLE Sense](https://store.arduino.cc/nano-33-ble-sense) +* [Arduino Nano 33 IoT](https://store.arduino.cc/nano-33-iot) +* [Arduino Nano RP2040 Connect](https://store.arduino.cc/nano-rp2040-connect) * [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3) * [Arduino Zero](https://store.arduino.cc/usa/arduino-zero) * [BBC micro:bit](https://microbit.org/) @@ -96,6 +99,7 @@ The following 63 microcontroller boards are currently supported: * [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html) * [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html) * [ProductivityOpen P1AM-100](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html) +* [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/) * [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html) * [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html) * [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html) diff --git a/targets/nano-33-ble-sense.json b/targets/nano-33-ble-sense.json new file mode 100644 index 000000000..943829d2d --- /dev/null +++ b/targets/nano-33-ble-sense.json @@ -0,0 +1,3 @@ +{ + "inherits": ["nano-33-ble"] +} From e02f308d43ff43fa649f4129c15e0f3809420801 Mon Sep 17 00:00:00 2001 From: Yurii Soldak Date: Wed, 23 Jun 2021 15:29:15 +0200 Subject: [PATCH 04/29] rp2040: fix for nano-rp2040 board --- targets/nano-rp2040.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/nano-rp2040.json b/targets/nano-rp2040.json index fb74a2e74..a0222c970 100644 --- a/targets/nano-rp2040.json +++ b/targets/nano-rp2040.json @@ -5,6 +5,6 @@ "build-tags": ["nano_rp2040"], "linkerscript": "targets/pico.ld", "extra-files": [ - "targets/pico_boot_stage2.S" + "targets/pico-boot-stage2.S" ] } From e65592599cb6c3a0ffd73d5a021b9aa4e00959ae Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 25 Jun 2021 15:00:32 +0200 Subject: [PATCH 05/29] compiler: implement syscall.rawSyscallNoError in inline assembly This makes it possible to call syscall.Getpid() on Linux, for example. These syscalls never return an error so don't need any error checking. --- compiler/compiler.go | 4 +++- compiler/syscall.go | 38 ++++++++++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/compiler/compiler.go b/compiler/compiler.go index cc696d5b0..7841cd656 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -23,7 +23,7 @@ import ( // Version of the compiler pacakge. Must be incremented each time the compiler // package changes in a way that affects the generated LLVM module. // This version is independent of the TinyGo version number. -const Version = 11 // last change: change method name globals +const Version = 12 // last change: implement syscall.rawSyscallNoError func init() { llvm.InitializeAllTargets() @@ -1310,6 +1310,8 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error) return b.emitCSROperation(instr) case strings.HasPrefix(name, "syscall.Syscall"): return b.createSyscall(instr) + case strings.HasPrefix(name, "syscall.rawSyscallNoError"): + return b.createRawSyscallNoError(instr) case strings.HasPrefix(name, "runtime/volatile.Load"): return b.createVolatileLoad(instr) case strings.HasPrefix(name, "runtime/volatile.Store"): diff --git a/compiler/syscall.go b/compiler/syscall.go index 5b93e9ec1..6a0bd3287 100644 --- a/compiler/syscall.go +++ b/compiler/syscall.go @@ -10,11 +10,11 @@ import ( "tinygo.org/x/go-llvm" ) -// createSyscall emits an inline system call instruction, depending on the -// target OS/arch. -func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { +// createRawSyscall creates a system call with the provided system call number +// and returns the result as a single integer (the system call result). The +// result is not further interpreted. +func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) { num := b.getValue(call.Args[0]) - var syscallResult llvm.Value switch { case b.GOARCH == "amd64": if b.GOOS == "darwin" { @@ -57,7 +57,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { constraints += ",~{rcx},~{r11}" fnType := llvm.FunctionType(b.uintptrType, argTypes, false) target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel) - syscallResult = b.CreateCall(target, args, "") + return b.CreateCall(target, args, ""), nil case b.GOARCH == "386" && b.GOOS == "linux": // Sources: // syscall(2) man page @@ -83,7 +83,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { } fnType := llvm.FunctionType(b.uintptrType, argTypes, false) target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel) - syscallResult = b.CreateCall(target, args, "") + return b.CreateCall(target, args, ""), nil case b.GOARCH == "arm" && b.GOOS == "linux": // Implement the EABI system call convention for Linux. // Source: syscall(2) man page. @@ -115,7 +115,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { } fnType := llvm.FunctionType(b.uintptrType, argTypes, false) target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0) - syscallResult = b.CreateCall(target, args, "") + return b.CreateCall(target, args, ""), nil case b.GOARCH == "arm64" && b.GOOS == "linux": // Source: syscall(2) man page. args := []llvm.Value{} @@ -147,10 +147,19 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { constraints += ",~{x16},~{x17}" // scratch registers fnType := llvm.FunctionType(b.uintptrType, argTypes, false) target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0) - syscallResult = b.CreateCall(target, args, "") + return b.CreateCall(target, args, ""), nil default: return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH) } +} + +// createSyscall emits instructions for the syscall.Syscall* family of +// functions, depending on the target OS/arch. +func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { + syscallResult, err := b.createRawSyscall(call) + if err != nil { + return syscallResult, err + } switch b.GOOS { case "linux", "freebsd": // Return values: r0, r1 uintptr, err Errno @@ -190,3 +199,16 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH) } } + +// createRawSyscallNoError emits instructions for the Linux-specific +// syscall.rawSyscallNoError function. +func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, error) { + syscallResult, err := b.createRawSyscall(call) + if err != nil { + return syscallResult, err + } + retval := llvm.ConstNull(b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType}, false)) + retval = b.CreateInsertValue(retval, syscallResult, 0, "") + retval = b.CreateInsertValue(retval, llvm.ConstInt(b.uintptrType, 0, false), 1, "") + return retval, nil +} From 75298bb84bcb966998ca00f3cc5506a9757a5038 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Fri, 25 Jun 2021 15:06:17 +0200 Subject: [PATCH 06/29] os: implement process related functions This commit implements various process related functions like os.Getuid() and os.Getpid(). It also implements or improves this support in the syscall package if it isn't available yet. --- src/os/exec.go | 12 +++++++++++ src/os/file.go | 5 ----- src/os/proc.go | 28 ++++++++++++++++++++++++ src/syscall/proc_emulated.go | 13 +++++++++++ src/syscall/proc_hosted.go | 37 ++++++++++++++++++++++++++++++++ src/syscall/syscall_baremetal.go | 6 ------ src/syscall/syscall_libc.go | 4 ---- testdata/stdlib.go | 9 ++++++++ 8 files changed, 99 insertions(+), 15 deletions(-) create mode 100644 src/syscall/proc_emulated.go create mode 100644 src/syscall/proc_hosted.go diff --git a/src/os/exec.go b/src/os/exec.go index 66cc79999..8bc544ba2 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -1,6 +1,18 @@ package os +import "syscall" + type Signal interface { String() string Signal() // to distinguish from other Stringers } + +// Getpid returns the process id of the caller, or -1 if unavailable. +func Getpid() int { + return syscall.Getpid() +} + +// Getppid returns the process id of the caller's parent, or -1 if unavailable. +func Getppid() int { + return syscall.Getppid() +} diff --git a/src/os/file.go b/src/os/file.go index a7aa40430..4d90bdde5 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -196,8 +196,3 @@ func Readlink(name string) (string, error) { func TempDir() string { return "/tmp" } - -// Getpid is a stub (for now), always returning 1 -func Getpid() int { - return 1 -} diff --git a/src/os/proc.go b/src/os/proc.go index d3bfb1270..fe2245f36 100644 --- a/src/os/proc.go +++ b/src/os/proc.go @@ -24,3 +24,31 @@ func runtime_args() []string // in package runtime func Exit(code int) { syscall.Exit(code) } + +// Getuid returns the numeric user id of the caller. +// +// On non-POSIX systems, it returns -1. +func Getuid() int { + return syscall.Getuid() +} + +// Geteuid returns the numeric effective user id of the caller. +// +// On non-POSIX systems, it returns -1. +func Geteuid() int { + return syscall.Geteuid() +} + +// Getgid returns the numeric group id of the caller. +// +// On non-POSIX systems, it returns -1. +func Getgid() int { + return syscall.Getgid() +} + +// Getegid returns the numeric effective group id of the caller. +// +// On non-POSIX systems, it returns -1. +func Getegid() int { + return syscall.Getegid() +} diff --git a/src/syscall/proc_emulated.go b/src/syscall/proc_emulated.go new file mode 100644 index 000000000..89b22e818 --- /dev/null +++ b/src/syscall/proc_emulated.go @@ -0,0 +1,13 @@ +// +build baremetal wasi wasm + +// This file emulates some process-related functions that are only available +// under a real operating system. + +package syscall + +func Getuid() int { return -1 } +func Geteuid() int { return -1 } +func Getgid() int { return -1 } +func Getegid() int { return -1 } +func Getpid() int { return -1 } +func Getppid() int { return -1 } diff --git a/src/syscall/proc_hosted.go b/src/syscall/proc_hosted.go new file mode 100644 index 000000000..5f52a4ca8 --- /dev/null +++ b/src/syscall/proc_hosted.go @@ -0,0 +1,37 @@ +// +build !baremetal,!wasi,!wasm + +// This file assumes there is a libc available that runs on a real operating +// system. + +package syscall + +func Getuid() int { return int(libc_getuid()) } +func Geteuid() int { return int(libc_geteuid()) } +func Getgid() int { return int(libc_getgid()) } +func Getegid() int { return int(libc_getegid()) } +func Getpid() int { return int(libc_getpid()) } +func Getppid() int { return int(libc_getppid()) } + +// uid_t getuid(void) +//export getuid +func libc_getuid() int32 + +// gid_t getgid(void) +//export getgid +func libc_getgid() int32 + +// uid_t geteuid(void) +//export geteuid +func libc_geteuid() int32 + +// gid_t getegid(void) +//export getegid +func libc_getegid() int32 + +// gid_t getpid(void) +//export getpid +func libc_getpid() int32 + +// gid_t getppid(void) +//export getppid +func libc_getppid() int32 diff --git a/src/syscall/syscall_baremetal.go b/src/syscall/syscall_baremetal.go index 28fa39ba8..4f0c6e530 100644 --- a/src/syscall/syscall_baremetal.go +++ b/src/syscall/syscall_baremetal.go @@ -98,14 +98,8 @@ type ProcAttr struct { type SysProcAttr struct { } -func Getegid() int { return 1 } -func Geteuid() int { return 1 } -func Getgid() int { return 1 } func Getgroups() ([]int, error) { return []int{1}, nil } -func Getppid() int { return 2 } -func Getpid() int { return 3 } func Gettimeofday(tv *Timeval) error { return ENOSYS } -func Getuid() int { return 1 } func Kill(pid int, signum Signal) error { return ENOSYS } func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { return 0, ENOSYS diff --git a/src/syscall/syscall_libc.go b/src/syscall/syscall_libc.go index 80675f191..bc6359630 100644 --- a/src/syscall/syscall_libc.go +++ b/src/syscall/syscall_libc.go @@ -62,10 +62,6 @@ func Kill(pid int, sig Signal) (err error) { return ENOSYS // TODO } -func Getpid() (pid int) { - panic("unimplemented: getpid") // TODO -} - func Getenv(key string) (value string, found bool) { data := append([]byte(key), 0) raw := libc_getenv(&data[0]) diff --git a/testdata/stdlib.go b/testdata/stdlib.go index e6d6677b6..55237ff68 100644 --- a/testdata/stdlib.go +++ b/testdata/stdlib.go @@ -5,6 +5,7 @@ import ( "math/rand" "os" "strings" + "syscall" ) func main() { @@ -13,6 +14,14 @@ func main() { fmt.Println("stdout:", os.Stdout.Name()) fmt.Println("stderr:", os.Stderr.Name()) + // Package syscall, this mostly checks whether the calls don't trigger an error. + syscall.Getuid() + syscall.Geteuid() + syscall.Getgid() + syscall.Getegid() + syscall.Getpid() + syscall.Getppid() + // package math/rand fmt.Println("pseudorandom number:", rand.Int31()) From 96e863f0f37cef0e8f36cb0d5f1c94fe062bc03d Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 1 Jun 2021 13:27:58 +0200 Subject: [PATCH 07/29] all: add a flag to the command line to select the serial implementation This can be very useful for some purposes: * It makes it possible to disable the UART in cases where it is not needed or needs to be disabled to conserve power. * It makes it possible to disable the serial output to reduce code size, which may be important for some chips. Sometimes, a few kB can be saved this way. * It makes it possible to override the default, for example you might want to use an actual UART to debug the USB-CDC implementation. It also lowers the dependency on having machine.Serial defined, which is often not defined when targeting a chip. Eventually, we might want to make it possible to write `-target=nrf52` or `-target=atmega328p` for example to target the chip itself with no board specific assumptions. The defaults don't change. I checked this by running `make smoketest` before and after and comparing the results. --- Makefile | 2 + compileopts/config.go | 14 +++++- compileopts/options.go | 11 +++++ compileopts/target.go | 1 + main.go | 2 + src/machine/board_arduino_mkr1000.go | 2 - src/machine/board_arduino_zero.go | 2 - src/machine/board_atsamd21.go | 2 - src/machine/board_atsame54-xpro.go | 2 - src/machine/board_bluepill.go | 2 +- src/machine/board_circuitplay_bluefruit.go | 2 - src/machine/board_clue_alpha.go | 5 --- src/machine/board_esp32-coreboard-v2.go | 2 - src/machine/board_feather-m4-can.go | 2 - src/machine/board_feather-m4.go | 2 - src/machine/board_feather-nrf52840.go | 5 --- src/machine/board_feather-stm32f405.go | 2 +- src/machine/board_grandcentral-m4.go | 2 - src/machine/board_hifive1b.go | 2 +- src/machine/board_itsybitsy-m4.go | 2 - src/machine/board_itsybitsy-nrf52840.go | 5 --- src/machine/board_lgt92.go | 2 +- src/machine/board_maixbit.go | 2 +- src/machine/board_metro-m4-airlift.go | 2 - src/machine/board_microbit-v2.go | 2 +- src/machine/board_microbit.go | 2 +- src/machine/board_nicenano.go | 5 --- src/machine/board_nodemcu.go | 2 - src/machine/board_nrf52840-mdk-usb-dongle.go | 3 -- src/machine/board_nrf52840-mdk.go | 3 -- src/machine/board_nucleof103rb.go | 2 +- src/machine/board_nucleof722ze.go | 2 +- src/machine/board_nucleol031k6.go | 2 +- src/machine/board_nucleol432kc.go | 2 +- src/machine/board_nucleol552ze.go | 2 +- src/machine/board_particle_argon.go | 2 +- src/machine/board_particle_boron.go | 2 +- src/machine/board_particle_xenon.go | 2 +- src/machine/board_pca10031.go | 2 +- src/machine/board_pca10040.go | 2 +- src/machine/board_pca10056.go | 2 +- src/machine/board_pca10059.go | 5 --- src/machine/board_pinetime-devkit0.go | 2 +- src/machine/board_pybadge.go | 2 - src/machine/board_pygamer.go | 2 - src/machine/board_pyportal.go | 2 - src/machine/board_reelboard.go | 2 +- src/machine/board_stm32f4disco.go | 2 +- src/machine/board_teensy36.go | 2 + src/machine/board_teensy40.go | 6 +-- src/machine/board_wioterminal.go | 2 - src/machine/board_x9pro.go | 2 +- src/machine/machine_atmega.go | 2 +- src/machine/machine_esp32.go | 2 + src/machine/machine_esp8266.go | 2 + src/machine/machine_generic.go | 12 ++--- src/machine/machine_rp2040.go | 2 +- src/machine/serial-none.go | 6 +++ src/machine/serial-uart.go | 6 +++ src/machine/serial-usb.go | 6 +++ src/machine/serial.go | 46 ++++++++++++++++++++ src/machine/uart.go | 6 --- targets/arduino-mkr1000.json | 1 + targets/arduino-zero.json | 1 + targets/atmega1280.json | 1 + targets/atmega1284p.json | 1 + targets/atmega2560.json | 1 + targets/atmega328p.json | 1 + targets/atsamd21e18a.json | 1 + targets/atsamd21g18a.json | 1 + targets/atsame54-xpro.json | 1 + targets/bluepill.json | 1 + targets/circuitplay-bluefruit.json | 1 + targets/clue-alpha.json | 1 + targets/esp32.json | 1 + targets/feather-m4-can.json | 1 + targets/feather-m4.json | 1 + targets/feather-nrf52840.json | 1 + targets/feather-stm32f405.json | 1 + targets/grandcentral-m4.json | 1 + targets/hifive1-qemu.json | 1 + targets/hifive1b.json | 1 + targets/itsybitsy-m4.json | 1 + targets/itsybitsy-nrf52840.json | 1 + targets/lgt92.json | 1 + targets/maixbit.json | 1 + targets/metro-m4-airlift.json | 1 + targets/microbit-v2.json | 1 + targets/microbit.json | 1 + targets/nicenano.json | 1 + targets/nodemcu.json | 3 +- targets/nrf52840-mdk-usb-dongle.json | 1 + targets/nrf52840-mdk.json | 1 + targets/nucleo-f103rb.json | 1 + targets/nucleo-f722ze.json | 1 + targets/nucleo-l031k6.json | 1 + targets/nucleo-l432kc.json | 1 + targets/nucleo-l552ze.json | 1 + targets/particle-3rd-gen.json | 1 + targets/pca10031.json | 1 + targets/pca10040.json | 1 + targets/pca10056.json | 1 + targets/pca10059.json | 1 + targets/pico.json | 1 + targets/pinetime-devkit0.json | 1 + targets/pybadge.json | 1 + targets/pygamer.json | 1 + targets/pyportal.json | 1 + targets/reelboard.json | 1 + targets/stm32f4disco.json | 1 + targets/teensy36.json | 1 + targets/teensy40.json | 1 + targets/wioterminal.json | 1 + targets/x9pro.json | 1 + 114 files changed, 185 insertions(+), 104 deletions(-) create mode 100644 src/machine/serial-none.go create mode 100644 src/machine/serial-uart.go create mode 100644 src/machine/serial-usb.go create mode 100644 src/machine/serial.go diff --git a/Makefile b/Makefile index 6abdc261d..1d6cac87f 100644 --- a/Makefile +++ b/Makefile @@ -436,6 +436,8 @@ endif @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=pca10040 -opt=1 examples/blinky1 @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=pca10040 -serial=none examples/echo + @$(MD5SUM) test.hex $(TINYGO) build -o test.nro -target=nintendoswitch examples/serial @$(MD5SUM) test.nro $(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go diff --git a/compileopts/config.go b/compileopts/config.go index 821aa8313..a60f778e0 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -55,7 +55,7 @@ func (c *Config) GOARCH() string { // BuildTags returns the complete list of build tags used during this build. func (c *Config) BuildTags() []string { - tags := append(c.Target.BuildTags, []string{"tinygo", "gc." + c.GC(), "scheduler." + c.Scheduler()}...) + tags := append(c.Target.BuildTags, []string{"tinygo", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...) for i := 1; i <= c.GoMinorVersion; i++ { tags = append(tags, fmt.Sprintf("go1.%d", i)) } @@ -113,6 +113,18 @@ func (c *Config) Scheduler() string { return "coroutines" } +// Serial returns the serial implementation for this build configuration: uart, +// usb (meaning USB-CDC), or none. +func (c *Config) Serial() string { + if c.Options.Serial != "" { + return c.Options.Serial + } + if c.Target.Serial != "" { + return c.Target.Serial + } + return "none" +} + // OptLevels returns the optimization level (0-2), size level (0-2), and inliner // threshold as used in the LLVM optimization pipeline. func (c *Config) OptLevels() (optLevel, sizeLevel int, inlinerThreshold uint) { diff --git a/compileopts/options.go b/compileopts/options.go index 10c143b80..7e7bfcafc 100644 --- a/compileopts/options.go +++ b/compileopts/options.go @@ -9,6 +9,7 @@ import ( var ( validGCOptions = []string{"none", "leaking", "extalloc", "conservative"} validSchedulerOptions = []string{"none", "tasks", "coroutines"} + validSerialOptions = []string{"none", "uart", "usb"} validPrintSizeOptions = []string{"none", "short", "full"} validPanicStrategyOptions = []string{"print", "trap"} validOptOptions = []string{"none", "0", "1", "2", "s", "z"} @@ -22,6 +23,7 @@ type Options struct { GC string PanicStrategy string Scheduler string + Serial string PrintIR bool DumpSSA bool VerifyIR bool @@ -59,6 +61,15 @@ func (o *Options) Verify() error { } } + if o.Serial != "" { + valid := isInArray(validSerialOptions, o.Serial) + if !valid { + return fmt.Errorf(`invalid serial option '%s': valid values are %s`, + o.Serial, + strings.Join(validSerialOptions, ", ")) + } + } + if o.PrintSizes != "" { valid := isInArray(validPrintSizeOptions, o.PrintSizes) if !valid { diff --git a/compileopts/target.go b/compileopts/target.go index 4fb62fce3..ba5f73826 100644 --- a/compileopts/target.go +++ b/compileopts/target.go @@ -31,6 +31,7 @@ type TargetSpec struct { BuildTags []string `json:"build-tags"` GC string `json:"gc"` Scheduler string `json:"scheduler"` + Serial string `json:"serial"` // which serial output to use (uart, usb, none) Linker string `json:"linker"` RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt) Libc string `json:"libc"` diff --git a/main.go b/main.go index 24d943624..7c3ee96df 100644 --- a/main.go +++ b/main.go @@ -1009,6 +1009,7 @@ func main() { gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, conservative)") panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)") scheduler := flag.String("scheduler", "", "which scheduler to use (none, coroutines, tasks)") + serial := flag.String("serial", "", "which serial output to use (none, uart, usb)") printIR := flag.Bool("printir", false, "print LLVM IR") dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA") verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR") @@ -1081,6 +1082,7 @@ func main() { GC: *gc, PanicStrategy: *panicStrategy, Scheduler: *scheduler, + Serial: *serial, PrintIR: *printIR, DumpSSA: *dumpSSA, VerifyIR: *verifyIR, diff --git a/src/machine/board_arduino_mkr1000.go b/src/machine/board_arduino_mkr1000.go index 863faeeb6..30ad48e90 100644 --- a/src/machine/board_arduino_mkr1000.go +++ b/src/machine/board_arduino_mkr1000.go @@ -47,8 +47,6 @@ const ( LED = D6 ) -var Serial = USB - // USBCDC pins const ( USBCDC_DM_PIN Pin = PA24 diff --git a/src/machine/board_arduino_zero.go b/src/machine/board_arduino_zero.go index 773515c99..651eea821 100644 --- a/src/machine/board_arduino_zero.go +++ b/src/machine/board_arduino_zero.go @@ -35,8 +35,6 @@ const ( LED3 Pin = PB03 // RX LED ) -var Serial = USB - // ADC pins const ( AREF Pin = PA03 diff --git a/src/machine/board_atsamd21.go b/src/machine/board_atsamd21.go index 800c4cb30..3b11b452a 100644 --- a/src/machine/board_atsamd21.go +++ b/src/machine/board_atsamd21.go @@ -74,5 +74,3 @@ const ( PB30 Pin = 62 PB31 Pin = 63 ) - -var Serial = USB diff --git a/src/machine/board_atsame54-xpro.go b/src/machine/board_atsame54-xpro.go index 01ae282c1..c61324b64 100644 --- a/src/machine/board_atsame54-xpro.go +++ b/src/machine/board_atsame54-xpro.go @@ -15,8 +15,6 @@ const ( BUTTON = PB31 ) -var Serial = USB - const ( // https://ww1.microchip.com/downloads/en/DeviceDoc/70005321A.pdf diff --git a/src/machine/board_bluepill.go b/src/machine/board_bluepill.go index ce925025f..bbfdac8bb 100644 --- a/src/machine/board_bluepill.go +++ b/src/machine/board_bluepill.go @@ -17,7 +17,7 @@ const ( BUTTON = PA0 ) -var Serial = UART1 +var DefaultUART = UART1 // UART pins const ( diff --git a/src/machine/board_circuitplay_bluefruit.go b/src/machine/board_circuitplay_bluefruit.go index 967672495..a65861b27 100644 --- a/src/machine/board_circuitplay_bluefruit.go +++ b/src/machine/board_circuitplay_bluefruit.go @@ -57,8 +57,6 @@ const ( UART_RX_PIN = P0_30 // PORTB ) -var Serial = USB - // I2C pins const ( SDA_PIN = P0_05 // I2C0 external diff --git a/src/machine/board_clue_alpha.go b/src/machine/board_clue_alpha.go index b421dccce..67c2ad7ef 100644 --- a/src/machine/board_clue_alpha.go +++ b/src/machine/board_clue_alpha.go @@ -104,11 +104,6 @@ const ( UART_TX_PIN = D1 ) -// Serial is the USB device -var ( - Serial = USB -) - // I2C pins const ( SDA_PIN = D20 // I2C0 external diff --git a/src/machine/board_esp32-coreboard-v2.go b/src/machine/board_esp32-coreboard-v2.go index b1d61d87e..0145fe4ea 100644 --- a/src/machine/board_esp32-coreboard-v2.go +++ b/src/machine/board_esp32-coreboard-v2.go @@ -68,8 +68,6 @@ const ( ADC3 Pin = IO39 ) -var Serial = UART0 - // UART0 pins const ( UART_TX_PIN = IO1 diff --git a/src/machine/board_feather-m4-can.go b/src/machine/board_feather-m4-can.go index 7911f5561..a954ce9cb 100644 --- a/src/machine/board_feather-m4-can.go +++ b/src/machine/board_feather-m4-can.go @@ -47,8 +47,6 @@ const ( WS2812 = D8 ) -var Serial = USB - // USBCDC pins const ( USBCDC_DM_PIN = PA24 diff --git a/src/machine/board_feather-m4.go b/src/machine/board_feather-m4.go index 394191366..86158ed64 100644 --- a/src/machine/board_feather-m4.go +++ b/src/machine/board_feather-m4.go @@ -40,8 +40,6 @@ const ( WS2812 = D8 ) -var Serial = USB - // USBCDC pins const ( USBCDC_DM_PIN = PA24 diff --git a/src/machine/board_feather-nrf52840.go b/src/machine/board_feather-nrf52840.go index 641a9de81..488d9608b 100644 --- a/src/machine/board_feather-nrf52840.go +++ b/src/machine/board_feather-nrf52840.go @@ -76,11 +76,6 @@ const ( UART_TX_PIN = D1 ) -// Serial is the USB device -var ( - Serial = USB -) - // I2C pins const ( SDA_PIN = D22 // I2C0 external diff --git a/src/machine/board_feather-stm32f405.go b/src/machine/board_feather-stm32f405.go index 4bf1744b9..ebba9edc8 100644 --- a/src/machine/board_feather-stm32f405.go +++ b/src/machine/board_feather-stm32f405.go @@ -141,7 +141,7 @@ var ( TxAltFuncSelector: AF7_USART1_2_3, RxAltFuncSelector: AF7_USART1_2_3, } - Serial = UART1 + DefaultUART = UART1 ) func initUART() { diff --git a/src/machine/board_grandcentral-m4.go b/src/machine/board_grandcentral-m4.go index 014eda801..c1b629c9e 100644 --- a/src/machine/board_grandcentral-m4.go +++ b/src/machine/board_grandcentral-m4.go @@ -142,8 +142,6 @@ const ( WS2812 = NEOPIXEL_PIN ) -var Serial = USB - // UART pins const ( UART1_RX_PIN = D0 // (PB25) diff --git a/src/machine/board_hifive1b.go b/src/machine/board_hifive1b.go index 7ce225ccf..d16225a68 100644 --- a/src/machine/board_hifive1b.go +++ b/src/machine/board_hifive1b.go @@ -35,7 +35,7 @@ const ( LED_BLUE = P21 ) -var Serial = UART0 +var DefaultUART = UART0 const ( // TODO: figure out the pin numbers for these. diff --git a/src/machine/board_itsybitsy-m4.go b/src/machine/board_itsybitsy-m4.go index 282f9087a..099ceed46 100644 --- a/src/machine/board_itsybitsy-m4.go +++ b/src/machine/board_itsybitsy-m4.go @@ -37,8 +37,6 @@ const ( LED = D13 ) -var Serial = USB - // USBCDC pins const ( USBCDC_DM_PIN = PA24 diff --git a/src/machine/board_itsybitsy-nrf52840.go b/src/machine/board_itsybitsy-nrf52840.go index 64aeed506..fc9b23f25 100644 --- a/src/machine/board_itsybitsy-nrf52840.go +++ b/src/machine/board_itsybitsy-nrf52840.go @@ -70,11 +70,6 @@ const ( UART_TX_PIN = D1 ) -// Serial is the USB device -var ( - Serial = USB -) - // I2C pins const ( SDA_PIN = D21 // I2C0 external diff --git a/src/machine/board_lgt92.go b/src/machine/board_lgt92.go index 97e1fa2ab..e043dcd77 100644 --- a/src/machine/board_lgt92.go +++ b/src/machine/board_lgt92.go @@ -54,7 +54,7 @@ const ( I2C0_SDA_PIN = PA10 ) -var Serial = UART0 +var DefaultUART = UART0 var ( diff --git a/src/machine/board_maixbit.go b/src/machine/board_maixbit.go index 766054d0d..e2c551b0e 100644 --- a/src/machine/board_maixbit.go +++ b/src/machine/board_maixbit.go @@ -52,7 +52,7 @@ const ( LED_BLUE = D14 ) -var Serial = UART0 +var DefaultUART = UART0 // Default pins for UARTHS. const ( diff --git a/src/machine/board_metro-m4-airlift.go b/src/machine/board_metro-m4-airlift.go index 276defa92..4aa248150 100644 --- a/src/machine/board_metro-m4-airlift.go +++ b/src/machine/board_metro-m4-airlift.go @@ -41,8 +41,6 @@ const ( WS2812 = D40 ) -var Serial = USB - // USBCDC pins const ( USBCDC_DM_PIN = PA24 diff --git a/src/machine/board_microbit-v2.go b/src/machine/board_microbit-v2.go index a034e2ef8..38a9dad50 100644 --- a/src/machine/board_microbit-v2.go +++ b/src/machine/board_microbit-v2.go @@ -12,7 +12,7 @@ const ( BUTTONB Pin = P11 ) -var Serial = UART0 +var DefaultUART = UART0 // UART pins const ( diff --git a/src/machine/board_microbit.go b/src/machine/board_microbit.go index 5b0ac2bff..b4af49f8d 100644 --- a/src/machine/board_microbit.go +++ b/src/machine/board_microbit.go @@ -12,7 +12,7 @@ const ( BUTTONB Pin = 26 ) -var Serial = UART0 +var DefaultUART = UART0 // UART pins const ( diff --git a/src/machine/board_nicenano.go b/src/machine/board_nicenano.go index 213fdb339..94511bf9f 100644 --- a/src/machine/board_nicenano.go +++ b/src/machine/board_nicenano.go @@ -54,11 +54,6 @@ const ( UART_TX_PIN = P0_08 ) -// Serial is the USB device -var ( - Serial = USB -) - // I2C pins const ( SDA_PIN = P0_17 // I2C0 external diff --git a/src/machine/board_nodemcu.go b/src/machine/board_nodemcu.go index 4177f80c4..f9f1af4f9 100644 --- a/src/machine/board_nodemcu.go +++ b/src/machine/board_nodemcu.go @@ -20,8 +20,6 @@ const ( // Onboard blue LED (on the AI-Thinker module). const LED = D4 -var Serial = UART0 - // SPI pins const ( SPI0_SCK_PIN = D5 diff --git a/src/machine/board_nrf52840-mdk-usb-dongle.go b/src/machine/board_nrf52840-mdk-usb-dongle.go index e4923f4e9..57a3d1976 100644 --- a/src/machine/board_nrf52840-mdk-usb-dongle.go +++ b/src/machine/board_nrf52840-mdk-usb-dongle.go @@ -23,9 +23,6 @@ const ( UART_RX_PIN Pin = NoPin ) -// Serial is the USB device -var Serial = USB - // I2C pins (unused) const ( SDA_PIN = NoPin diff --git a/src/machine/board_nrf52840-mdk.go b/src/machine/board_nrf52840-mdk.go index d9dc41305..fbc42861b 100644 --- a/src/machine/board_nrf52840-mdk.go +++ b/src/machine/board_nrf52840-mdk.go @@ -18,9 +18,6 @@ const ( UART_RX_PIN Pin = 19 ) -// Serial is the USB device -var Serial = USB - // I2C pins (unused) const ( SDA_PIN = NoPin diff --git a/src/machine/board_nucleof103rb.go b/src/machine/board_nucleof103rb.go index 6fa0c27c7..22580e20b 100644 --- a/src/machine/board_nucleof103rb.go +++ b/src/machine/board_nucleof103rb.go @@ -34,7 +34,7 @@ var ( Buffer: NewRingBuffer(), Bus: stm32.USART2, } - Serial = UART2 + DefaultUART = UART2 ) func init() { diff --git a/src/machine/board_nucleof722ze.go b/src/machine/board_nucleof722ze.go index 003e8fc75..41d3f2849 100644 --- a/src/machine/board_nucleof722ze.go +++ b/src/machine/board_nucleof722ze.go @@ -38,7 +38,7 @@ var ( TxAltFuncSelector: UART_ALT_FN, RxAltFuncSelector: UART_ALT_FN, } - Serial = UART1 + DefaultUART = UART1 ) func init() { diff --git a/src/machine/board_nucleol031k6.go b/src/machine/board_nucleol031k6.go index a758ba932..fe85f276b 100644 --- a/src/machine/board_nucleol031k6.go +++ b/src/machine/board_nucleol031k6.go @@ -76,7 +76,7 @@ var ( TxAltFuncSelector: 4, RxAltFuncSelector: 4, } - Serial = UART1 + DefaultUART = UART1 // I2C1 is documented, alias to I2C0 as well I2C1 = &I2C{ diff --git a/src/machine/board_nucleol432kc.go b/src/machine/board_nucleol432kc.go index d44e0f4fd..bfebd1eed 100644 --- a/src/machine/board_nucleol432kc.go +++ b/src/machine/board_nucleol432kc.go @@ -78,7 +78,7 @@ var ( TxAltFuncSelector: 7, RxAltFuncSelector: 3, } - Serial = UART1 + DefaultUART = UART1 // I2C1 is documented, alias to I2C0 as well I2C1 = &I2C{ diff --git a/src/machine/board_nucleol552ze.go b/src/machine/board_nucleol552ze.go index 98e2d5c1f..a0d3ee522 100644 --- a/src/machine/board_nucleol552ze.go +++ b/src/machine/board_nucleol552ze.go @@ -38,7 +38,7 @@ var ( TxAltFuncSelector: UART_ALT_FN, RxAltFuncSelector: UART_ALT_FN, } - Serial = UART1 + DefaultUART = UART1 ) const ( diff --git a/src/machine/board_particle_argon.go b/src/machine/board_particle_argon.go index 1130eaf82..9427029f4 100644 --- a/src/machine/board_particle_argon.go +++ b/src/machine/board_particle_argon.go @@ -41,7 +41,7 @@ const ( // UART var ( - Serial = UART0 + DefaultUART = UART0 ) const ( diff --git a/src/machine/board_particle_boron.go b/src/machine/board_particle_boron.go index 6c2f70a80..b6a2c3e54 100644 --- a/src/machine/board_particle_boron.go +++ b/src/machine/board_particle_boron.go @@ -41,7 +41,7 @@ const ( // UART var ( - Serial = UART0 + DefaultUART = UART0 ) const ( diff --git a/src/machine/board_particle_xenon.go b/src/machine/board_particle_xenon.go index a6e48ae0a..0b25f373b 100644 --- a/src/machine/board_particle_xenon.go +++ b/src/machine/board_particle_xenon.go @@ -41,7 +41,7 @@ const ( // UART var ( - Serial = UART0 + DefaultUART = UART0 ) const ( diff --git a/src/machine/board_pca10031.go b/src/machine/board_pca10031.go index fbddfb232..122c00d20 100644 --- a/src/machine/board_pca10031.go +++ b/src/machine/board_pca10031.go @@ -19,7 +19,7 @@ const ( LED_BLUE Pin = 23 ) -var Serial = UART0 +var DefaultUART = UART0 // UART pins const ( diff --git a/src/machine/board_pca10040.go b/src/machine/board_pca10040.go index 10e2ab2ed..f425ca37c 100644 --- a/src/machine/board_pca10040.go +++ b/src/machine/board_pca10040.go @@ -23,7 +23,7 @@ const ( BUTTON4 Pin = 16 ) -var Serial = UART0 +var DefaultUART = UART0 // UART pins for NRF52840-DK const ( diff --git a/src/machine/board_pca10056.go b/src/machine/board_pca10056.go index 824bd3f01..783629465 100644 --- a/src/machine/board_pca10056.go +++ b/src/machine/board_pca10056.go @@ -22,7 +22,7 @@ const ( BUTTON4 Pin = 25 ) -var Serial = UART0 +var DefaultUART = UART0 // UART pins const ( diff --git a/src/machine/board_pca10059.go b/src/machine/board_pca10059.go index 5079534aa..7f6167913 100644 --- a/src/machine/board_pca10059.go +++ b/src/machine/board_pca10059.go @@ -34,11 +34,6 @@ const ( UART_RX_PIN Pin = NoPin ) -// Serial is the USB device -var ( - Serial = USB -) - // I2C pins (unused) const ( SDA_PIN = NoPin diff --git a/src/machine/board_pinetime-devkit0.go b/src/machine/board_pinetime-devkit0.go index 5222010bd..b9669c84d 100644 --- a/src/machine/board_pinetime-devkit0.go +++ b/src/machine/board_pinetime-devkit0.go @@ -17,7 +17,7 @@ const ( LED3 = LCD_BACKLIGHT_LOW ) -var Serial = UART0 +var DefaultUART = UART0 // UART pins for PineTime. Note that RX is set to NoPin as RXD is not listed in // the PineTime schematic 1.0: diff --git a/src/machine/board_pybadge.go b/src/machine/board_pybadge.go index 3ff24a160..e175da683 100644 --- a/src/machine/board_pybadge.go +++ b/src/machine/board_pybadge.go @@ -67,8 +67,6 @@ const ( BUTTON_B_MASK = 128 ) -var Serial = USB - // USBCDC pins const ( USBCDC_DM_PIN = PA24 diff --git a/src/machine/board_pygamer.go b/src/machine/board_pygamer.go index 890c3d3d9..f537f8529 100644 --- a/src/machine/board_pygamer.go +++ b/src/machine/board_pygamer.go @@ -70,8 +70,6 @@ const ( BUTTON_B_MASK = 128 ) -var Serial = USB - // USBCDC pins const ( USBCDC_DM_PIN = PA24 diff --git a/src/machine/board_pyportal.go b/src/machine/board_pyportal.go index 7e28de44a..ff2fcb7fe 100644 --- a/src/machine/board_pyportal.go +++ b/src/machine/board_pyportal.go @@ -95,8 +95,6 @@ const ( LED = D13 ) -var Serial = USB - // USBCDC pins const ( USBCDC_DM_PIN = PA24 diff --git a/src/machine/board_reelboard.go b/src/machine/board_reelboard.go index 70eb70539..7fd715bb7 100644 --- a/src/machine/board_reelboard.go +++ b/src/machine/board_reelboard.go @@ -29,7 +29,7 @@ const ( BUTTON Pin = 7 ) -var Serial = UART0 +var DefaultUART = UART0 // UART pins const ( diff --git a/src/machine/board_stm32f4disco.go b/src/machine/board_stm32f4disco.go index 49f5650fd..cc3711a19 100644 --- a/src/machine/board_stm32f4disco.go +++ b/src/machine/board_stm32f4disco.go @@ -38,7 +38,7 @@ var ( TxAltFuncSelector: AF7_USART1_2_3, RxAltFuncSelector: AF7_USART1_2_3, } - Serial = UART1 + DefaultUART = UART1 ) // set up RX IRQ handler. Follow similar pattern for other UARTx instances diff --git a/src/machine/board_teensy36.go b/src/machine/board_teensy36.go index 0808b4b35..8fa71f6e9 100644 --- a/src/machine/board_teensy36.go +++ b/src/machine/board_teensy36.go @@ -87,6 +87,8 @@ var ( TeensyUART5 = UART4 ) +var DefaultUART = UART0 + const ( defaultUART0RX = D00 defaultUART0TX = D01 diff --git a/src/machine/board_teensy40.go b/src/machine/board_teensy40.go index 54ae4e6b4..289edadd8 100644 --- a/src/machine/board_teensy40.go +++ b/src/machine/board_teensy40.go @@ -136,9 +136,9 @@ const ( ) var ( - Serial = UART1 - UART1 = &_UART1 - _UART1 = UART{ + DefaultUART = UART1 + UART1 = &_UART1 + _UART1 = UART{ Bus: nxp.LPUART6, Buffer: NewRingBuffer(), txBuffer: NewRingBuffer(), diff --git a/src/machine/board_wioterminal.go b/src/machine/board_wioterminal.go index abbe55500..57bbff1b5 100644 --- a/src/machine/board_wioterminal.go +++ b/src/machine/board_wioterminal.go @@ -325,8 +325,6 @@ const ( OUTPUT_CTR_3V3 = PC15 ) -var Serial = USB - // USBCDC pins const ( USBCDC_DM_PIN = PIN_USB_DM diff --git a/src/machine/board_x9pro.go b/src/machine/board_x9pro.go index 63d7257a5..111dcf5fd 100644 --- a/src/machine/board_x9pro.go +++ b/src/machine/board_x9pro.go @@ -27,4 +27,4 @@ const ( const HasLowFrequencyCrystal = true -var Serial = UART0 +var DefaultUART = UART0 diff --git a/src/machine/machine_atmega.go b/src/machine/machine_atmega.go index fe6536e7f..6e2b59cf1 100644 --- a/src/machine/machine_atmega.go +++ b/src/machine/machine_atmega.go @@ -122,7 +122,7 @@ func (i2c *I2C) readByte() byte { } // Always use UART0 as the serial output. -var Serial = UART0 +var DefaultUART = UART0 // UART var ( diff --git a/src/machine/machine_esp32.go b/src/machine/machine_esp32.go index ee3f61de1..b5f801b49 100644 --- a/src/machine/machine_esp32.go +++ b/src/machine/machine_esp32.go @@ -251,6 +251,8 @@ func (p Pin) mux() *volatile.Register32 { } } +var DefaultUART = UART0 + var ( UART0 = &_UART0 _UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()} diff --git a/src/machine/machine_esp8266.go b/src/machine/machine_esp8266.go index e8a9ecf64..72c672066 100644 --- a/src/machine/machine_esp8266.go +++ b/src/machine/machine_esp8266.go @@ -139,6 +139,8 @@ func (p Pin) PortMaskClear() (*uint32, uint32) { return &esp.GPIO.GPIO_OUT_W1TC.Reg, 1 << p } +var DefaultUART = UART0 + // UART0 is a hardware UART that supports both TX and RX. var UART0 = &_UART0 var _UART0 = UART{Buffer: NewRingBuffer()} diff --git a/src/machine/machine_generic.go b/src/machine/machine_generic.go index 98dca2df8..70551e27a 100644 --- a/src/machine/machine_generic.go +++ b/src/machine/machine_generic.go @@ -11,6 +11,12 @@ var ( USB = &UART{100} ) +// The Serial port always points to the default UART in a simulated environment. +// +// TODO: perhaps this should be a special serial object that outputs via WASI +// stdout calls. +var Serial = UART0 + const ( PinInput PinMode = iota PinOutput @@ -118,12 +124,6 @@ type UART struct { Bus uint8 } -type UARTConfig struct { - BaudRate uint32 - TX Pin - RX Pin -} - // Configure the UART. func (uart *UART) Configure(config UARTConfig) { uartConfigure(uart.Bus, config.TX, config.RX) diff --git a/src/machine/machine_rp2040.go b/src/machine/machine_rp2040.go index f7580967a..297c92e3b 100644 --- a/src/machine/machine_rp2040.go +++ b/src/machine/machine_rp2040.go @@ -108,7 +108,7 @@ var ( } ) -var Serial = UART0 +var DefaultUART = UART0 func init() { UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt) diff --git a/src/machine/serial-none.go b/src/machine/serial-none.go new file mode 100644 index 000000000..22e94cc90 --- /dev/null +++ b/src/machine/serial-none.go @@ -0,0 +1,6 @@ +// +build baremetal,serial.none + +package machine + +// Serial is a null device: writes to it are ignored. +var Serial = NullSerial{} diff --git a/src/machine/serial-uart.go b/src/machine/serial-uart.go new file mode 100644 index 000000000..d3edf832f --- /dev/null +++ b/src/machine/serial-uart.go @@ -0,0 +1,6 @@ +// +build baremetal,serial.uart + +package machine + +// Serial is implemented via the default (usually the first) UART on the chip. +var Serial = DefaultUART diff --git a/src/machine/serial-usb.go b/src/machine/serial-usb.go new file mode 100644 index 000000000..476d4b0cf --- /dev/null +++ b/src/machine/serial-usb.go @@ -0,0 +1,6 @@ +// +build baremetal,serial.usb + +package machine + +// Serial is implemented via USB (USB-CDC). +var Serial = USB diff --git a/src/machine/serial.go b/src/machine/serial.go new file mode 100644 index 000000000..fd02d6ca0 --- /dev/null +++ b/src/machine/serial.go @@ -0,0 +1,46 @@ +package machine + +import "errors" + +var errNoByte = errors.New("machine: no byte read") + +// UARTConfig is a struct with which a UART (or similar object) can be +// configured. The baud rate is usually respected, but TX and RX may be ignored +// depending on the chip and the type of object. +type UARTConfig struct { + BaudRate uint32 + TX Pin + RX Pin +} + +// NullSerial is a serial version of /dev/null (or null router): it drops +// everything that is written to it. +type NullSerial struct { +} + +// Configure does nothing: the null serial has no configuration. +func (ns NullSerial) Configure(config UARTConfig) error { + return nil +} + +// WriteByte is a no-op: the null serial doesn't write bytes. +func (ns NullSerial) WriteByte(b byte) error { + return nil +} + +// ReadByte always returns an error because there aren't any bytes to read. +func (ns NullSerial) ReadByte() (byte, error) { + return 0, errNoByte +} + +// Buffered returns how many bytes are buffered in the UART. It always returns 0 +// as there are no bytes to read. +func (ns NullSerial) Buffered() int { + return 0 +} + +// Write is a no-op: none of the data is being written and it will not return an +// error. +func (ns NullSerial) Write(p []byte) (n int, err error) { + return len(p), nil +} diff --git a/src/machine/uart.go b/src/machine/uart.go index 701fb9797..8fbac8711 100644 --- a/src/machine/uart.go +++ b/src/machine/uart.go @@ -23,12 +23,6 @@ const ( ParityOdd UARTParity = 2 ) -type UARTConfig struct { - BaudRate uint32 - TX Pin - RX Pin -} - // To implement the UART interface for a board, you must declare a concrete type as follows: // // type UART struct { diff --git a/targets/arduino-mkr1000.json b/targets/arduino-mkr1000.json index a5abfca52..89d7bfa69 100644 --- a/targets/arduino-mkr1000.json +++ b/targets/arduino-mkr1000.json @@ -1,6 +1,7 @@ { "inherits": ["atsamd21g18a"], "build-tags": ["arduino_mkr1000"], + "serial": "usb", "flash-command": "bossac -i -e -w -v -R -U --port={port} --offset=0x2000 {bin}", "flash-1200-bps-reset": "true" } diff --git a/targets/arduino-zero.json b/targets/arduino-zero.json index 50483512e..045bb8c05 100644 --- a/targets/arduino-zero.json +++ b/targets/arduino-zero.json @@ -1,6 +1,7 @@ { "inherits": ["atsamd21g18a"], "build-tags": ["arduino_zero"], + "serial": "usb", "flash-command": "bossac -i -e -w -v -R -U --port={port} --offset=0x2000 {bin}", "flash-1200-bps-reset": "true" } diff --git a/targets/atmega1280.json b/targets/atmega1280.json index 21324a36d..2b0bfde7b 100644 --- a/targets/atmega1280.json +++ b/targets/atmega1280.json @@ -2,6 +2,7 @@ "inherits": ["avr"], "cpu": "atmega1280", "build-tags": ["atmega1280", "atmega"], + "serial": "uart", "cflags": [ "-mmcu=atmega1280" ], diff --git a/targets/atmega1284p.json b/targets/atmega1284p.json index 2c2d29e18..3fbecd4b7 100644 --- a/targets/atmega1284p.json +++ b/targets/atmega1284p.json @@ -2,6 +2,7 @@ "inherits": ["avr"], "cpu": "atmega1284p", "build-tags": ["atmega1284p", "atmega"], + "serial": "uart", "cflags": [ "-mmcu=atmega1284p" ], diff --git a/targets/atmega2560.json b/targets/atmega2560.json index f460c9c89..9caa088cf 100644 --- a/targets/atmega2560.json +++ b/targets/atmega2560.json @@ -2,6 +2,7 @@ "inherits": ["avr"], "cpu": "atmega2560", "build-tags": ["atmega2560", "atmega"], + "serial": "uart", "cflags": [ "-mmcu=atmega2560" ], diff --git a/targets/atmega328p.json b/targets/atmega328p.json index 7a10eceba..24a272147 100644 --- a/targets/atmega328p.json +++ b/targets/atmega328p.json @@ -2,6 +2,7 @@ "inherits": ["avr"], "cpu": "atmega328p", "build-tags": ["atmega328p", "atmega", "avr5"], + "serial": "uart", "cflags": [ "-mmcu=atmega328p" ], diff --git a/targets/atsamd21e18a.json b/targets/atsamd21e18a.json index 0fcf50675..92b671c9f 100644 --- a/targets/atsamd21e18a.json +++ b/targets/atsamd21e18a.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m0plus"], "build-tags": ["atsamd21e18a", "atsamd21e18", "atsamd21", "sam"], + "serial": "usb", "linkerscript": "targets/atsamd21.ld", "extra-files": [ "src/device/sam/atsamd21e18a.s" diff --git a/targets/atsamd21g18a.json b/targets/atsamd21g18a.json index 956afba54..db46c9628 100644 --- a/targets/atsamd21g18a.json +++ b/targets/atsamd21g18a.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m0plus"], "build-tags": ["atsamd21g18a", "atsamd21g18", "atsamd21", "sam"], + "serial": "usb", "linkerscript": "targets/atsamd21.ld", "extra-files": [ "src/device/sam/atsamd21g18a.s" diff --git a/targets/atsame54-xpro.json b/targets/atsame54-xpro.json index 631df8cfb..1ab7c4eea 100644 --- a/targets/atsame54-xpro.json +++ b/targets/atsame54-xpro.json @@ -1,6 +1,7 @@ { "inherits": ["atsame54p20a"], "build-tags": ["atsame54_xpro"], + "serial": "usb", "flash-method": "openocd", "openocd-interface": "cmsis-dap", "default-stack-size": 4096 diff --git a/targets/bluepill.json b/targets/bluepill.json index 9f1e4b004..752261f4d 100644 --- a/targets/bluepill.json +++ b/targets/bluepill.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m3"], "build-tags": ["bluepill", "stm32f103", "stm32f1", "stm32"], + "serial": "uart", "linkerscript": "targets/stm32.ld", "extra-files": [ "src/device/stm32/stm32f103.s" diff --git a/targets/circuitplay-bluefruit.json b/targets/circuitplay-bluefruit.json index 24bf5577f..0c1f6ae3b 100644 --- a/targets/circuitplay-bluefruit.json +++ b/targets/circuitplay-bluefruit.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52840"], "build-tags": ["circuitplay_bluefruit","nrf52840_reset_uf2", "softdevice", "s140v6"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "serial-port": ["acm:239a:8045", "acm:239a:45"], diff --git a/targets/clue-alpha.json b/targets/clue-alpha.json index e2594ea7d..ebe83f79d 100644 --- a/targets/clue-alpha.json +++ b/targets/clue-alpha.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52840"], "build-tags": ["clue_alpha","nrf52840_reset_uf2", "softdevice", "s140v6"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "CLUEBOOT", diff --git a/targets/esp32.json b/targets/esp32.json index 3559e8920..ded861624 100644 --- a/targets/esp32.json +++ b/targets/esp32.json @@ -3,6 +3,7 @@ "cpu": "esp32", "build-tags": ["esp32", "esp"], "scheduler": "tasks", + "serial": "uart", "linker": "xtensa-esp32-elf-ld", "default-stack-size": 2048, "cflags": [ diff --git a/targets/feather-m4-can.json b/targets/feather-m4-can.json index 190d4d8f9..22222622f 100644 --- a/targets/feather-m4-can.json +++ b/targets/feather-m4-can.json @@ -1,6 +1,7 @@ { "inherits": ["atsame51j19a"], "build-tags": ["feather_m4_can"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "FTHRCANBOOT", diff --git a/targets/feather-m4.json b/targets/feather-m4.json index ccf06ec54..408946297 100644 --- a/targets/feather-m4.json +++ b/targets/feather-m4.json @@ -1,6 +1,7 @@ { "inherits": ["atsamd51j19a"], "build-tags": ["feather_m4"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "FEATHERBOOT", diff --git a/targets/feather-nrf52840.json b/targets/feather-nrf52840.json index f0b706186..c334f7065 100644 --- a/targets/feather-nrf52840.json +++ b/targets/feather-nrf52840.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52840"], "build-tags": ["feather_nrf52840","nrf52840_reset_uf2", "softdevice", "s140v6"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "FTHR840BOOT", diff --git a/targets/feather-stm32f405.json b/targets/feather-stm32f405.json index d3bb1dc9c..3d824d1ed 100644 --- a/targets/feather-stm32f405.json +++ b/targets/feather-stm32f405.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m4"], "build-tags": ["feather_stm32f405", "stm32f405", "stm32f4", "stm32"], + "serial": "uart", "automatic-stack-size": false, "linkerscript": "targets/stm32f405.ld", "extra-files": [ diff --git a/targets/grandcentral-m4.json b/targets/grandcentral-m4.json index 4545dfd9f..7b374c98e 100644 --- a/targets/grandcentral-m4.json +++ b/targets/grandcentral-m4.json @@ -1,6 +1,7 @@ { "inherits": ["atsamd51p20a"], "build-tags": ["grandcentral_m4"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "GCM4BOOT", diff --git a/targets/hifive1-qemu.json b/targets/hifive1-qemu.json index 9a50cee64..60fe27a4d 100644 --- a/targets/hifive1-qemu.json +++ b/targets/hifive1-qemu.json @@ -1,6 +1,7 @@ { "inherits": ["fe310"], "build-tags": ["hifive1b", "qemu"], + "serial": "uart", "linkerscript": "targets/hifive1-qemu.ld", "emulator": ["qemu-system-riscv32", "-machine", "sifive_e", "-nographic", "-kernel"] } diff --git a/targets/hifive1b.json b/targets/hifive1b.json index bd561ae0b..1084531b3 100644 --- a/targets/hifive1b.json +++ b/targets/hifive1b.json @@ -1,6 +1,7 @@ { "inherits": ["fe310"], "build-tags": ["hifive1b"], + "serial": "uart", "linkerscript": "targets/hifive1b.ld", "flash-method": "msd", "msd-volume-name": "HiFive", diff --git a/targets/itsybitsy-m4.json b/targets/itsybitsy-m4.json index 9c7a634ba..af4027a4a 100644 --- a/targets/itsybitsy-m4.json +++ b/targets/itsybitsy-m4.json @@ -1,6 +1,7 @@ { "inherits": ["atsamd51g19a"], "build-tags": ["itsybitsy_m4"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "serial-port": ["acm:239a:802b", "acm:239a:002b"], diff --git a/targets/itsybitsy-nrf52840.json b/targets/itsybitsy-nrf52840.json index b8637fd00..aab873c18 100644 --- a/targets/itsybitsy-nrf52840.json +++ b/targets/itsybitsy-nrf52840.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52840"], "build-tags": ["itsybitsy_nrf52840","nrf52840_reset_uf2", "softdevice", "s140v6"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "ITSY840BOOT", diff --git a/targets/lgt92.json b/targets/lgt92.json index 82c603a9b..23bc84dd2 100644 --- a/targets/lgt92.json +++ b/targets/lgt92.json @@ -5,6 +5,7 @@ "build-tags": [ "lgt92" ], + "serial": "uart", "linkerscript": "targets/stm32l072czt6.ld", "flash-method": "openocd", "openocd-interface": "stlink-v2", diff --git a/targets/maixbit.json b/targets/maixbit.json index 21322072a..8f6216162 100644 --- a/targets/maixbit.json +++ b/targets/maixbit.json @@ -1,6 +1,7 @@ { "inherits": ["k210"], "build-tags": ["maixbit"], + "serial": "uart", "linkerscript": "targets/maixbit.ld", "flash-command": "kflash -p {port} --noansi --verbose {bin}" } diff --git a/targets/metro-m4-airlift.json b/targets/metro-m4-airlift.json index a282ac55a..5783a4336 100644 --- a/targets/metro-m4-airlift.json +++ b/targets/metro-m4-airlift.json @@ -1,6 +1,7 @@ { "inherits": ["atsamd51j19a"], "build-tags": ["metro_m4_airlift"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "METROM4BOOT", diff --git a/targets/microbit-v2.json b/targets/microbit-v2.json index 33a9392eb..c8c7461c3 100644 --- a/targets/microbit-v2.json +++ b/targets/microbit-v2.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52833"], "build-tags": ["microbit_v2"], + "serial": "uart", "flash-method": "msd", "openocd-interface": "cmsis-dap", "msd-volume-name": "MICROBIT", diff --git a/targets/microbit.json b/targets/microbit.json index 1b677c5d3..a890100da 100644 --- a/targets/microbit.json +++ b/targets/microbit.json @@ -1,6 +1,7 @@ { "inherits": ["nrf51"], "build-tags": ["microbit"], + "serial": "uart", "flash-method": "msd", "openocd-interface": "cmsis-dap", "msd-volume-name": "MICROBIT", diff --git a/targets/nicenano.json b/targets/nicenano.json index 3a406ea5c..b18a0c1ca 100644 --- a/targets/nicenano.json +++ b/targets/nicenano.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52840"], "build-tags": ["nicenano","nrf52840_reset_uf2", "softdevice", "s140v6"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "NICENANO", diff --git a/targets/nodemcu.json b/targets/nodemcu.json index c1fdbec06..c8c6c4039 100644 --- a/targets/nodemcu.json +++ b/targets/nodemcu.json @@ -1,4 +1,5 @@ { "inherits": ["esp8266"], - "build-tags": ["nodemcu"] + "build-tags": ["nodemcu"], + "serial": "uart" } diff --git a/targets/nrf52840-mdk-usb-dongle.json b/targets/nrf52840-mdk-usb-dongle.json index fa4c72256..34e76b779 100644 --- a/targets/nrf52840-mdk-usb-dongle.json +++ b/targets/nrf52840-mdk-usb-dongle.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52840"], "build-tags": ["nrf52840_mdk_usb_dongle", "nrf52840_reset_uf2", "softdevice", "s140v6"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "MDK-DONGLE", diff --git a/targets/nrf52840-mdk.json b/targets/nrf52840-mdk.json index 244b3d96d..03528e501 100644 --- a/targets/nrf52840-mdk.json +++ b/targets/nrf52840-mdk.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52840"], "build-tags": ["nrf52840_mdk"], + "serial": "usb", "flash-method": "openocd", "openocd-interface": "cmsis-dap" } diff --git a/targets/nucleo-f103rb.json b/targets/nucleo-f103rb.json index 1c12af847..723c5eef9 100644 --- a/targets/nucleo-f103rb.json +++ b/targets/nucleo-f103rb.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m3"], "build-tags": ["nucleof103rb", "stm32f103", "stm32f1","stm32"], + "serial": "uart", "linkerscript": "targets/stm32f103rb.ld", "extra-files": [ "src/device/stm32/stm32f103.s" diff --git a/targets/nucleo-f722ze.json b/targets/nucleo-f722ze.json index 25a388b9e..f426b332d 100644 --- a/targets/nucleo-f722ze.json +++ b/targets/nucleo-f722ze.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m7"], "build-tags": ["nucleof722ze", "stm32f7x2", "stm32f7", "stm32"], + "serial": "uart", "linkerscript": "targets/stm32f7x2zetx.ld", "extra-files": [ "src/device/stm32/stm32f7x2.s" diff --git a/targets/nucleo-l031k6.json b/targets/nucleo-l031k6.json index 928dd43dc..eed8f38f0 100644 --- a/targets/nucleo-l031k6.json +++ b/targets/nucleo-l031k6.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m0"], "build-tags": ["nucleol031k6", "stm32l031", "stm32l0x1", "stm32l0", "stm32"], + "serial": "uart", "linkerscript": "targets/stm32l031k6.ld", "extra-files": [ "src/device/stm32/stm32l0x1.s" diff --git a/targets/nucleo-l432kc.json b/targets/nucleo-l432kc.json index f13c8bde4..028b034b0 100644 --- a/targets/nucleo-l432kc.json +++ b/targets/nucleo-l432kc.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m4"], "build-tags": ["nucleol432kc", "stm32l432", "stm32l4x2", "stm32l4", "stm32"], + "serial": "uart", "linkerscript": "targets/stm32l4x2.ld", "extra-files": [ "src/device/stm32/stm32l4x2.s" diff --git a/targets/nucleo-l552ze.json b/targets/nucleo-l552ze.json index 56e286ab5..044b58371 100644 --- a/targets/nucleo-l552ze.json +++ b/targets/nucleo-l552ze.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m33"], "build-tags": ["nucleol552ze", "stm32l552", "stm32l5x2", "stm32l5", "stm32"], + "serial": "uart", "linkerscript": "targets/stm32l5x2xe.ld", "extra-files": [ "src/device/stm32/stm32l552.s" diff --git a/targets/particle-3rd-gen.json b/targets/particle-3rd-gen.json index 2229319e7..ef39a7340 100644 --- a/targets/particle-3rd-gen.json +++ b/targets/particle-3rd-gen.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52840"], "build-tags": ["particle_3rd_gen"], + "serial": "uart", "flash-method": "openocd", "openocd-interface": "cmsis-dap" } diff --git a/targets/pca10031.json b/targets/pca10031.json index cccae828a..8af365cc8 100644 --- a/targets/pca10031.json +++ b/targets/pca10031.json @@ -1,6 +1,7 @@ { "inherits": ["nrf51"], "build-tags": ["pca10031"], + "serial": "uart", "flash-command": "nrfjprog -f nrf51 --sectorerase --program {hex} --reset", "openocd-interface": "cmsis-dap" } diff --git a/targets/pca10040.json b/targets/pca10040.json index 7685be427..b751b3bd6 100644 --- a/targets/pca10040.json +++ b/targets/pca10040.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52"], "build-tags": ["pca10040"], + "serial": "uart", "flash-method": "openocd", "flash-command": "nrfjprog -f nrf52 --sectorerase --program {hex} --reset", "openocd-interface": "jlink", diff --git a/targets/pca10056.json b/targets/pca10056.json index fc0acaa0a..b604624cf 100644 --- a/targets/pca10056.json +++ b/targets/pca10056.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52840"], "build-tags": ["pca10056"], + "serial": "uart", "flash-method": "command", "flash-command": "nrfjprog -f nrf52 --sectorerase --program {hex} --reset", "msd-volume-name": "JLINK", diff --git a/targets/pca10059.json b/targets/pca10059.json index 5a8eb8265..b5286e989 100644 --- a/targets/pca10059.json +++ b/targets/pca10059.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52840"], "build-tags": ["pca10059"], + "serial": "usb", "linkerscript": "targets/pca10059.ld", "binary-format": "nrf-dfu", "flash-command": "nrfutil dfu usb-serial -pkg {zip} -p {port} -b 115200" diff --git a/targets/pico.json b/targets/pico.json index 011d5110f..36e3ba30e 100644 --- a/targets/pico.json +++ b/targets/pico.json @@ -3,6 +3,7 @@ "rp2040" ], "build-tags": ["pico"], + "serial": "uart", "linkerscript": "targets/pico.ld", "extra-files": [ "targets/pico-boot-stage2.S" diff --git a/targets/pinetime-devkit0.json b/targets/pinetime-devkit0.json index adbe874ae..8655769ee 100644 --- a/targets/pinetime-devkit0.json +++ b/targets/pinetime-devkit0.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52"], "build-tags": ["pinetime_devkit0"], + "serial": "uart", "flash-method": "openocd", "flash-command": "nrfjprog -f nrf52 --sectorerase --program {hex} --reset", "openocd-interface": "jlink", diff --git a/targets/pybadge.json b/targets/pybadge.json index b76b32469..15af8f8a9 100644 --- a/targets/pybadge.json +++ b/targets/pybadge.json @@ -1,6 +1,7 @@ { "inherits": ["atsamd51j19a"], "build-tags": ["pybadge"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "serial-port": ["acm:239a:8033", "acm:239a:33"], diff --git a/targets/pygamer.json b/targets/pygamer.json index 63dc34a18..03147e08a 100644 --- a/targets/pygamer.json +++ b/targets/pygamer.json @@ -1,6 +1,7 @@ { "inherits": ["atsamd51j19a"], "build-tags": ["pygamer"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "PYGAMERBOOT", diff --git a/targets/pyportal.json b/targets/pyportal.json index a26d82f08..abda3ab18 100644 --- a/targets/pyportal.json +++ b/targets/pyportal.json @@ -1,6 +1,7 @@ { "inherits": ["atsamd51j20a"], "build-tags": ["pyportal"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "serial-port": ["acm:239a:8035", "acm:239a:35", "acm:239a:8036"], diff --git a/targets/reelboard.json b/targets/reelboard.json index 60aeb1cfd..b6da0a449 100644 --- a/targets/reelboard.json +++ b/targets/reelboard.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52840"], "build-tags": ["reelboard"], + "serial": "uart", "flash-method": "msd", "msd-volume-name": "reel-board", "msd-firmware-name": "firmware.hex", diff --git a/targets/stm32f4disco.json b/targets/stm32f4disco.json index 622c5b0d6..4485c41d3 100644 --- a/targets/stm32f4disco.json +++ b/targets/stm32f4disco.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m4"], "build-tags": ["stm32f4disco", "stm32f407", "stm32f4", "stm32"], + "serial": "uart", "linkerscript": "targets/stm32f407.ld", "extra-files": [ "src/device/stm32/stm32f407.s" diff --git a/targets/teensy36.json b/targets/teensy36.json index c341511ec..253e39704 100644 --- a/targets/teensy36.json +++ b/targets/teensy36.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m4"], "build-tags": ["teensy36", "teensy", "mk66f18", "nxp"], + "serial": "uart", "linkerscript": "targets/nxpmk66f18.ld", "extra-files": [ "src/device/nxp/mk66f18.s", diff --git a/targets/teensy40.json b/targets/teensy40.json index d08b8d1dd..c530003b3 100644 --- a/targets/teensy40.json +++ b/targets/teensy40.json @@ -1,6 +1,7 @@ { "inherits": ["cortex-m7"], "build-tags": ["teensy40", "teensy", "mimxrt1062", "nxp"], + "serial": "uart", "automatic-stack-size": false, "default-stack-size": 4096, "linkerscript": "targets/mimxrt1062-teensy40.ld", diff --git a/targets/wioterminal.json b/targets/wioterminal.json index 093947e16..1f81b928f 100644 --- a/targets/wioterminal.json +++ b/targets/wioterminal.json @@ -1,6 +1,7 @@ { "inherits": ["atsamd51p19a"], "build-tags": ["wioterminal"], + "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "Arduino", diff --git a/targets/x9pro.json b/targets/x9pro.json index a9ecc0c83..9b966b4b9 100644 --- a/targets/x9pro.json +++ b/targets/x9pro.json @@ -1,6 +1,7 @@ { "inherits": ["nrf52"], "build-tags": ["x9pro"], + "serial": "uart", "flash-method": "openocd", "flash-command": "nrfjprog -f nrf52 --sectorerase --program {hex} --reset", "openocd-interface": "jlink", From 0e267dd2304cb45c42d51d54a57107e3f00ee6d8 Mon Sep 17 00:00:00 2001 From: deadprogram Date: Fri, 25 Jun 2021 18:20:44 +0200 Subject: [PATCH 08/29] targets: add serial key to JSON files for newly added rp2040 boards, and also nano-33-ble board Signed-off-by: deadprogram --- src/machine/board_nano-33-ble.go | 5 ----- targets/feather-rp2040.json | 1 + targets/nano-33-ble.json | 1 + targets/nano-rp2040.json | 1 + 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/machine/board_nano-33-ble.go b/src/machine/board_nano-33-ble.go index b8d68b0bd..4483f811d 100644 --- a/src/machine/board_nano-33-ble.go +++ b/src/machine/board_nano-33-ble.go @@ -70,11 +70,6 @@ const ( UART_TX_PIN = P1_03 ) -// Serial is the USB device -var ( - Serial = USB -) - // I2C pins const ( SDA_PIN = P0_31 diff --git a/targets/feather-rp2040.json b/targets/feather-rp2040.json index 45f6b60b6..955c2a887 100644 --- a/targets/feather-rp2040.json +++ b/targets/feather-rp2040.json @@ -2,6 +2,7 @@ "inherits": [ "rp2040" ], + "serial": "uart", "build-tags": ["feather_rp2040"], "linkerscript": "targets/feather-rp2040.ld", "extra-files": [ diff --git a/targets/nano-33-ble.json b/targets/nano-33-ble.json index c5381e9f4..bbf80da52 100644 --- a/targets/nano-33-ble.json +++ b/targets/nano-33-ble.json @@ -3,6 +3,7 @@ "build-tags": ["nano_33_ble", "nrf52840_reset_bossa"], "flash-command": "bossac_arduino2 -d -i -e -w -v -R --port={port} {bin}", "serial-port": ["acm:2341:805a", "acm:2341:005a"], + "serial": "usb", "flash-1200-bps-reset": "true", "linkerscript": "targets/nano-33-ble.ld" } diff --git a/targets/nano-rp2040.json b/targets/nano-rp2040.json index a0222c970..461e0746b 100644 --- a/targets/nano-rp2040.json +++ b/targets/nano-rp2040.json @@ -2,6 +2,7 @@ "inherits": [ "rp2040" ], + "serial": "uart", "build-tags": ["nano_rp2040"], "linkerscript": "targets/pico.ld", "extra-files": [ From e5453ebe27ff102f7319653162b4661e41ceace0 Mon Sep 17 00:00:00 2001 From: sago35 Date: Sat, 26 Jun 2021 12:09:40 +0900 Subject: [PATCH 09/29] machine/feather-nrf52840-sense: add board definition for Adafruit Feather nRF52840 Sense --- Makefile | 2 + README.md | 3 +- src/machine/board_feather-nrf52840-sense.go | 101 ++++++++++++++++++++ targets/feather-nrf52840-sense.json | 11 +++ 4 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 src/machine/board_feather-nrf52840-sense.go create mode 100644 targets/feather-nrf52840-sense.json diff --git a/Makefile b/Makefile index 1d6cac87f..b62956a56 100644 --- a/Makefile +++ b/Makefile @@ -336,6 +336,8 @@ smoketest: @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/blinky1 @$(MD5SUM) test.hex + $(TINYGO) build -size short -o test.hex -target=feather-nrf52840-sense examples/blinky1 + @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=itsybitsy-nrf52840 examples/blinky1 @$(MD5SUM) test.hex $(TINYGO) build -size short -o test.hex -target=qtpy examples/serial diff --git a/README.md b/README.md index f28f4eb8f..8f233d6ba 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for You can compile TinyGo programs for microcontrollers, WebAssembly and Linux. -The following 67 microcontroller boards are currently supported: +The following 68 microcontroller boards are currently supported: * [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333) * [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333) @@ -52,6 +52,7 @@ The following 67 microcontroller boards are currently supported: * [Adafruit Feather M4](https://www.adafruit.com/product/3857) * [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759) * [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062) +* [Adafruit Feather nRF52840 Sense](https://www.adafruit.com/product/4516) * [Adafruit Feather RP2040](https://www.adafruit.com/product/4884) * [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382) * [Adafruit Grand Central M4](https://www.adafruit.com/product/4064) diff --git a/src/machine/board_feather-nrf52840-sense.go b/src/machine/board_feather-nrf52840-sense.go new file mode 100644 index 000000000..4d8804f73 --- /dev/null +++ b/src/machine/board_feather-nrf52840-sense.go @@ -0,0 +1,101 @@ +// +build feather_nrf52840_sense + +package machine + +const HasLowFrequencyCrystal = true + +// GPIO Pins +const ( + D0 = P0_25 // UART TX + D1 = P0_24 // UART RX + D2 = P0_10 // NFC2 + D3 = P1_11 + D4 = P1_10 // LED2 + D5 = P1_08 + D6 = P0_07 + D7 = P1_02 // Button + D8 = P0_16 // NeoPixel + D9 = P0_26 + D10 = P0_27 + D11 = P0_06 + D12 = P0_08 + D13 = P1_09 // LED1 + D14 = P0_04 // A0 + D15 = P0_05 // A1 + D16 = P0_30 // A2 + D17 = P0_28 // A3 + D18 = P0_02 // A4 + D19 = P0_03 // A5 + D20 = P0_29 // Battery + D21 = P0_31 // AREF + D22 = P0_12 // I2C SDA + D23 = P0_11 // I2C SCL + D24 = P0_15 // SPI MISO + D25 = P0_13 // SPI MOSI + D26 = P0_14 // SPI SCK + D27 = P0_19 // QSPI CLK + D28 = P0_20 // QSPI CS + D29 = P0_17 // QSPI Data 0 + D30 = P0_22 // QSPI Data 1 + D31 = P0_23 // QSPI Data 2 + D32 = P0_21 // QSPI Data 3 + D33 = P0_09 // NFC1 (test point on bottom of board) +) + +// Analog Pins +const ( + A0 = D14 + A1 = D15 + A2 = D16 + A3 = D17 + A4 = D18 + A5 = D19 + A6 = D20 // Battery + A7 = D21 // ARef +) + +const ( + LED = D13 + LED1 = LED + LED2 = D4 + NEOPIXEL = D8 + WS2812 = D8 + BUTTON = D7 + + QSPI_SCK = D27 + QSPI_CS = D28 + QSPI_DATA0 = D29 + QSPI_DATA1 = D30 + QSPI_DATA2 = D31 + QSPI_DATA3 = D32 +) + +// UART0 pins (logical UART1) +const ( + UART_RX_PIN = D0 + UART_TX_PIN = D1 +) + +// I2C pins +const ( + SDA_PIN = D22 // I2C0 external + SCL_PIN = D23 // I2C0 external +) + +// SPI pins +const ( + SPI0_SCK_PIN = D26 // SCK + SPI0_SDO_PIN = D25 // SDO + SPI0_SDI_PIN = D24 // SDI +) + +// USB CDC identifiers +const ( + usb_STRING_PRODUCT = "Feather nRF52840 Express" + usb_STRING_MANUFACTURER = "Adafruit Industries LLC" +) + +var ( + usb_VID uint16 = 0x239A + usb_PID uint16 = 0x8088 +) diff --git a/targets/feather-nrf52840-sense.json b/targets/feather-nrf52840-sense.json new file mode 100644 index 000000000..d8210063f --- /dev/null +++ b/targets/feather-nrf52840-sense.json @@ -0,0 +1,11 @@ +{ + "inherits": ["nrf52840"], + "build-tags": ["feather_nrf52840_sense","nrf52840_reset_uf2", "softdevice", "s140v6"], + "serial": "usb", + "flash-1200-bps-reset": "true", + "flash-method": "msd", + "msd-volume-name": "FTHR840BOOT", + "msd-firmware-name": "firmware.uf2", + "uf2-family-id": "0xADA52840", + "linkerscript": "targets/circuitplay-bluefruit.ld" +} From e127ceac6761eb28579cf2b7278c2cd298451aac Mon Sep 17 00:00:00 2001 From: sago35 Date: Mon, 28 Jun 2021 15:18:00 +0900 Subject: [PATCH 10/29] machine/feather-nrf52840-sense: fix msd-volume-name --- targets/feather-nrf52840-sense.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/targets/feather-nrf52840-sense.json b/targets/feather-nrf52840-sense.json index d8210063f..a6735333f 100644 --- a/targets/feather-nrf52840-sense.json +++ b/targets/feather-nrf52840-sense.json @@ -4,7 +4,7 @@ "serial": "usb", "flash-1200-bps-reset": "true", "flash-method": "msd", - "msd-volume-name": "FTHR840BOOT", + "msd-volume-name": "FTHRSNSBOOT", "msd-firmware-name": "firmware.uf2", "uf2-family-id": "0xADA52840", "linkerscript": "targets/circuitplay-bluefruit.ld" From b00cfc001e626fc9fb665e72d4d9fbb556776d84 Mon Sep 17 00:00:00 2001 From: sago35 Date: Sat, 26 Jun 2021 13:41:44 +0900 Subject: [PATCH 11/29] targets: add serial and serial-port key to JSON files for adafruit boards --- targets/clue-alpha.json | 1 + targets/feather-m0.json | 2 ++ targets/feather-m4-can.json | 1 + targets/feather-m4.json | 1 + targets/feather-nrf52840-sense.json | 1 + targets/feather-nrf52840.json | 1 + targets/grandcentral-m4.json | 1 + targets/itsybitsy-m0.json | 2 ++ targets/itsybitsy-nrf52840.json | 1 + targets/matrixportal-m4.json | 2 ++ targets/metro-m4-airlift.json | 1 + targets/pygamer.json | 1 + targets/qtpy.json | 2 ++ targets/trinket-m0.json | 2 ++ 14 files changed, 19 insertions(+) diff --git a/targets/clue-alpha.json b/targets/clue-alpha.json index ebe83f79d..26088d531 100644 --- a/targets/clue-alpha.json +++ b/targets/clue-alpha.json @@ -2,6 +2,7 @@ "inherits": ["nrf52840"], "build-tags": ["clue_alpha","nrf52840_reset_uf2", "softdevice", "s140v6"], "serial": "usb", + "serial-port": ["acm:239a:8072", "acm:239a:0072", "acm:239a:0071", "acm:239a:8071"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "CLUEBOOT", diff --git a/targets/feather-m0.json b/targets/feather-m0.json index 9262833b3..f8070fb10 100644 --- a/targets/feather-m0.json +++ b/targets/feather-m0.json @@ -1,6 +1,8 @@ { "inherits": ["atsamd21g18a"], "build-tags": ["feather_m0"], + "serial": "usb", + "serial-port": ["acm:239a:801b", "acm:239a:001b", "acm:239a:800b", "acm:239a:000b", "acm:239a:0015"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "FEATHERBOOT", diff --git a/targets/feather-m4-can.json b/targets/feather-m4-can.json index 22222622f..1c5b67e86 100644 --- a/targets/feather-m4-can.json +++ b/targets/feather-m4-can.json @@ -2,6 +2,7 @@ "inherits": ["atsame51j19a"], "build-tags": ["feather_m4_can"], "serial": "usb", + "serial-port": ["acm:239a:80cd", "acm:239a:00cd"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "FTHRCANBOOT", diff --git a/targets/feather-m4.json b/targets/feather-m4.json index 408946297..4c33ddd8f 100644 --- a/targets/feather-m4.json +++ b/targets/feather-m4.json @@ -2,6 +2,7 @@ "inherits": ["atsamd51j19a"], "build-tags": ["feather_m4"], "serial": "usb", + "serial-port": ["acm:239a:8022", "acm:239a:0022"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "FEATHERBOOT", diff --git a/targets/feather-nrf52840-sense.json b/targets/feather-nrf52840-sense.json index a6735333f..b39c82105 100644 --- a/targets/feather-nrf52840-sense.json +++ b/targets/feather-nrf52840-sense.json @@ -2,6 +2,7 @@ "inherits": ["nrf52840"], "build-tags": ["feather_nrf52840_sense","nrf52840_reset_uf2", "softdevice", "s140v6"], "serial": "usb", + "serial-port": ["acm:239a:8087", "acm:239a:0087", "acm:239a:0088", "acm:239a:8088"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "FTHRSNSBOOT", diff --git a/targets/feather-nrf52840.json b/targets/feather-nrf52840.json index c334f7065..a4c491956 100644 --- a/targets/feather-nrf52840.json +++ b/targets/feather-nrf52840.json @@ -2,6 +2,7 @@ "inherits": ["nrf52840"], "build-tags": ["feather_nrf52840","nrf52840_reset_uf2", "softdevice", "s140v6"], "serial": "usb", + "serial-port": ["acm:239a:8029", "acm:239a:0029", "acm:239a:002a", "acm:239a:802a"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "FTHR840BOOT", diff --git a/targets/grandcentral-m4.json b/targets/grandcentral-m4.json index 7b374c98e..392b55502 100644 --- a/targets/grandcentral-m4.json +++ b/targets/grandcentral-m4.json @@ -2,6 +2,7 @@ "inherits": ["atsamd51p20a"], "build-tags": ["grandcentral_m4"], "serial": "usb", + "serial-port": ["acm:239a:8031", "acm:239a:0031", "acm:239a:0032"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "GCM4BOOT", diff --git a/targets/itsybitsy-m0.json b/targets/itsybitsy-m0.json index db9dd2cf9..0482dc6cb 100644 --- a/targets/itsybitsy-m0.json +++ b/targets/itsybitsy-m0.json @@ -1,6 +1,8 @@ { "inherits": ["atsamd21g18a"], "build-tags": ["itsybitsy_m0"], + "serial": "usb", + "serial-port": ["acm:239a:800f", "acm:239a:000f", "acm:239a:8012"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "ITSYBOOT", diff --git a/targets/itsybitsy-nrf52840.json b/targets/itsybitsy-nrf52840.json index aab873c18..d657b8a96 100644 --- a/targets/itsybitsy-nrf52840.json +++ b/targets/itsybitsy-nrf52840.json @@ -2,6 +2,7 @@ "inherits": ["nrf52840"], "build-tags": ["itsybitsy_nrf52840","nrf52840_reset_uf2", "softdevice", "s140v6"], "serial": "usb", + "serial-port": ["acm:239A:8052", "acm:239A:0052", "acm:239A:0051", "acm:239A:8051"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "ITSY840BOOT", diff --git a/targets/matrixportal-m4.json b/targets/matrixportal-m4.json index cca54a7e5..e9125f0e4 100644 --- a/targets/matrixportal-m4.json +++ b/targets/matrixportal-m4.json @@ -1,6 +1,8 @@ { "inherits": ["atsamd51j19a"], "build-tags": ["atsamd51j19a", "matrixportal_m4"], + "serial": "usb", + "serial-port": ["acm:239a:80c9", "acm:239a:00c9", "acm:239a:80ca"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "MATRIXBOOT", diff --git a/targets/metro-m4-airlift.json b/targets/metro-m4-airlift.json index 5783a4336..33ffd61cf 100644 --- a/targets/metro-m4-airlift.json +++ b/targets/metro-m4-airlift.json @@ -2,6 +2,7 @@ "inherits": ["atsamd51j19a"], "build-tags": ["metro_m4_airlift"], "serial": "usb", + "serial-port": ["acm:239A:8037", "acm:239A:0037"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "METROM4BOOT", diff --git a/targets/pygamer.json b/targets/pygamer.json index 03147e08a..4f4ab6e33 100644 --- a/targets/pygamer.json +++ b/targets/pygamer.json @@ -2,6 +2,7 @@ "inherits": ["atsamd51j19a"], "build-tags": ["pygamer"], "serial": "usb", + "serial-port": ["acm:239a:803d", "acm:239a:003d", "acm:239a:803e"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "PYGAMERBOOT", diff --git a/targets/qtpy.json b/targets/qtpy.json index 98821876a..53f1221b1 100644 --- a/targets/qtpy.json +++ b/targets/qtpy.json @@ -1,6 +1,8 @@ { "inherits": ["atsamd21e18a"], "build-tags": ["qtpy"], + "serial": "usb", + "serial-port": ["acm:239a:80cb", "acm:239a:00cb", "acm:239a:00cc"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "QTPY_BOOT", diff --git a/targets/trinket-m0.json b/targets/trinket-m0.json index af0e450ef..61bfc0a19 100644 --- a/targets/trinket-m0.json +++ b/targets/trinket-m0.json @@ -1,6 +1,8 @@ { "inherits": ["atsamd21e18a"], "build-tags": ["trinket_m0"], + "serial": "usb", + "serial-port": ["acm:239a:801e", "acm:239a:001e"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "TRINKETBOOT", From c8e231bc0b9aa276b2fb50050f4c1b412cfe77e5 Mon Sep 17 00:00:00 2001 From: sago35 Date: Sat, 26 Jun 2021 14:46:54 +0900 Subject: [PATCH 12/29] targets: add serial and serial-port key to JSON files for seeed boards --- targets/wioterminal.json | 1 + targets/xiao.json | 2 ++ 2 files changed, 3 insertions(+) diff --git a/targets/wioterminal.json b/targets/wioterminal.json index 1f81b928f..5564d0761 100644 --- a/targets/wioterminal.json +++ b/targets/wioterminal.json @@ -2,6 +2,7 @@ "inherits": ["atsamd51p19a"], "build-tags": ["wioterminal"], "serial": "usb", + "serial-port": ["acm:2886:002d", "acm:2886:802d"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "Arduino", diff --git a/targets/xiao.json b/targets/xiao.json index 50dee8f2a..80cc99d38 100644 --- a/targets/xiao.json +++ b/targets/xiao.json @@ -1,6 +1,8 @@ { "inherits": ["atsamd21g18a"], "build-tags": ["xiao"], + "serial": "usb", + "serial-port": ["acm:2886:802f", "acm:2886:002f"], "flash-1200-bps-reset": "true", "flash-method": "msd", "msd-volume-name": "Arduino", From 64d048c47c95bc0a70b4cff109afc1f9039705a4 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 24 Jun 2021 01:18:00 +0200 Subject: [PATCH 13/29] main: release version 0.19.0 --- CHANGELOG.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++ goenv/version.go | 2 +- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5fe0f0e30..9c427d9e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,69 @@ +0.19.0 +--- + +* **command line** + - don't consider compile-only tests as failing + - add -test flag for `tinygo list` + - escape commands while printing them with the -x flag + - make flash-command portable and safer to use + - use `extended-remote` instead of `remote` in GDB + - detect specific serial port IDs based on USB vid/pid + - add a flag to the command line to select the serial implementation +* **compiler** + - `cgo`: improve constant parser + - `compiler`: support chained interrupt handlers + - `compiler`: add support for running a builtin in a goroutine + - `compiler`: do not emit nil checks for loading closure variables + - `compiler`: skip context parameter when starting regular goroutine + - `compiler`: refactor method names + - `compiler`: add function and global section pragmas + - `compiler`: implement `syscall.rawSyscallNoError` in inline assembly + - `interp`: ignore inline assembly in markExternal + - `interp`: fix a bug in pointer cast workaround + - `loader`: fix testing a main package +* **standard library** + - `crypto/rand`: replace this package with a TinyGo version + - `machine`: make USBCDC global a pointer + - `machine`: make UART objects pointer receivers + - `machine`: define Serial as the default output + - `net`: add initial support for net.IP + - `net`: add more net compatibility + - `os`: add stub for os.ReadDir + - `os`: add FileMode constants from Go 1.16 + - `os`: add stubs required for net/http + - `os`: implement process related functions + - `reflect`: implement AppendSlice + - `reflect`: add stubs required for net/http + - `runtime`: make task.Data a 64-bit integer to avoid overflow + - `runtime`: expose memory stats + - `sync`: implement NewCond + - `syscall`: fix int type in libc version +* **targets** + - `cortexm`: do not disable interrupts on abort + - `cortexm`: bump default stack size to 2048 bytes + - `nrf`: avoid heap allocation in waitForEvent + - `nrf`: don't trigger a heap allocation in SPI.Transfer + - `nrf52840`: add support for flashing with the BOSSA tool + - `rp2040`: add support for GPIO input + - `rp2040`: add basic support for ADC + - `rp2040`: gpio and adc pin definitions + - `rp2040`: implement UART + - `rp2040`: patch elf to checksum 2nd stage boot + - `stm32`: add PWM for most chips + - `stm32`: add support for pin interrupts + - `stm32f103`: add support for PinInputPullup / PinInputPulldown + - `wasi`: remove wasm build tag +* **boards** + - `feather-rp2040`: add support for this board + - `feather-nrf52840-sense`: add board definition for this board + - `pca10059`: support flashing from Windows + - `nano-rp2040`: add this board + - `nano-33-ble`: add support for this board + - `pico`: add the Raspberry Pi Pico board with the new RP2040 chip + - `qtpy`: add pin for neopixels + - all: add definition for ws2812 for supported boards + + 0.18.0 --- diff --git a/goenv/version.go b/goenv/version.go index 909f330f4..c257e845e 100644 --- a/goenv/version.go +++ b/goenv/version.go @@ -12,7 +12,7 @@ import ( // Version of TinyGo. // Update this value before release of new version of software. -const Version = "0.19.0-dev" +const Version = "0.19.0" // GetGorootVersion returns the major and minor version for a given GOROOT path. // If the goroot cannot be determined, (0, 0) is returned. From 2d633e3a28b11254fc5bf643c1730bd5759c69c6 Mon Sep 17 00:00:00 2001 From: sago35 Date: Thu, 1 Jul 2021 18:44:15 +0900 Subject: [PATCH 14/29] version: update TinyGo version to 0.20.0-dev --- goenv/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/goenv/version.go b/goenv/version.go index c257e845e..e0fe0949c 100644 --- a/goenv/version.go +++ b/goenv/version.go @@ -12,7 +12,7 @@ import ( // Version of TinyGo. // Update this value before release of new version of software. -const Version = "0.19.0" +const Version = "0.20.0-dev" // GetGorootVersion returns the major and minor version for a given GOROOT path. // If the goroot cannot be determined, (0, 0) is returned. From 42785e08e88dcbcfbbb36e6b12f081de16c86093 Mon Sep 17 00:00:00 2001 From: Patricio Whittingslow Date: Tue, 29 Jun 2021 22:16:21 -0300 Subject: [PATCH 15/29] add MAC address implementation to net --- src/net/mac.go | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/src/net/mac.go b/src/net/mac.go index 13f505192..ea3b921f0 100644 --- a/src/net/mac.go +++ b/src/net/mac.go @@ -7,3 +7,93 @@ package net const hexDigit = "0123456789abcdef" + +// A HardwareAddr represents a physical hardware address. +type HardwareAddr []byte + +func (a HardwareAddr) String() string { + if len(a) == 0 { + return "" + } + buf := make([]byte, 0, len(a)*3-1) + for i, b := range a { + if i > 0 { + buf = append(buf, ':') + } + buf = append(buf, hexDigit[b>>4]) + buf = append(buf, hexDigit[b&0xF]) + } + return string(buf) +} + +// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, EUI-64, or a 20-octet +// IP over InfiniBand link-layer address using one of the following formats: +// 00:00:5e:00:53:01 +// 02:00:5e:10:00:00:00:01 +// 00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01 +// 00-00-5e-00-53-01 +// 02-00-5e-10-00-00-00-01 +// 00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01 +// 0000.5e00.5301 +// 0200.5e10.0000.0001 +// 0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001 +func ParseMAC(s string) (hw HardwareAddr, err error) { + if len(s) < 14 { + goto err + } + + if s[2] == ':' || s[2] == '-' { + if (len(s)+1)%3 != 0 { + goto err + } + n := (len(s) + 1) / 3 + if n != 6 && n != 8 && n != 20 { + goto err + } + hw = make(HardwareAddr, n) + for x, i := 0, 0; i < n; i++ { + var ok bool + if hw[i], ok = xtoi2(s[x:], s[2]); !ok { + goto err + } + x += 3 + } + } else if s[4] == '.' { + if (len(s)+1)%5 != 0 { + goto err + } + n := 2 * (len(s) + 1) / 5 + if n != 6 && n != 8 && n != 20 { + goto err + } + hw = make(HardwareAddr, n) + for x, i := 0, 0; i < n; i += 2 { + var ok bool + if hw[i], ok = xtoi2(s[x:x+2], 0); !ok { + goto err + } + if hw[i+1], ok = xtoi2(s[x+2:], s[4]); !ok { + goto err + } + x += 5 + } + } else { + goto err + } + return hw, nil + +err: + return nil, &AddrError{Err: "invalid MAC address", Addr: s} +} + +// xtoi2 converts the next two hex digits of s into a byte. +// If s is longer than 2 bytes then the third byte must be e. +// If the first two bytes of s are not hex digits or the third byte +// does not match e, false is returned. +func xtoi2(s string, e byte) (byte, bool) { + if len(s) > 2 && s[2] != e { + return 0, false + } + n, ei, ok := xtoi(s[:2]) + return byte(n), ok && ei == 2 +} From 444dded92cfaf870be3a590e13419af49f1192b0 Mon Sep 17 00:00:00 2001 From: soypat Date: Wed, 30 Jun 2021 08:49:39 -0300 Subject: [PATCH 16/29] move xtoi2 to parse.go --- src/net/mac.go | 12 ------------ src/net/parse.go | 12 ++++++++++++ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/net/mac.go b/src/net/mac.go index ea3b921f0..815b2738f 100644 --- a/src/net/mac.go +++ b/src/net/mac.go @@ -85,15 +85,3 @@ func ParseMAC(s string) (hw HardwareAddr, err error) { err: return nil, &AddrError{Err: "invalid MAC address", Addr: s} } - -// xtoi2 converts the next two hex digits of s into a byte. -// If s is longer than 2 bytes then the third byte must be e. -// If the first two bytes of s are not hex digits or the third byte -// does not match e, false is returned. -func xtoi2(s string, e byte) (byte, bool) { - if len(s) > 2 && s[2] != e { - return 0, false - } - n, ei, ok := xtoi(s[:2]) - return byte(n), ok && ei == 2 -} diff --git a/src/net/parse.go b/src/net/parse.go index 1255f918f..2a840c854 100644 --- a/src/net/parse.go +++ b/src/net/parse.go @@ -52,6 +52,18 @@ func xtoi(s string) (n int, i int, ok bool) { return n, i, true } +// xtoi2 converts the next two hex digits of s into a byte. +// If s is longer than 2 bytes then the third byte must be e. +// If the first two bytes of s are not hex digits or the third byte +// does not match e, false is returned. +func xtoi2(s string, e byte) (byte, bool) { + if len(s) > 2 && s[2] != e { + return 0, false + } + n, ei, ok := xtoi(s[:2]) + return byte(n), ok && ei == 2 +} + // Convert unsigned integer to decimal string. func uitoa(val uint) string { if val == 0 { // avoid string allocation From 0565b7c0e050f0cccbccdcbc1a9cee43462603d9 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Mon, 5 Jul 2021 01:50:52 +0200 Subject: [PATCH 17/29] cortexm: fix stack overflow because of unaligned stacks On ARM, the stack has to be aligned to 8 bytes on function calls, but not necessarily within a function. Leaf functions can take advantage of this by not keeping the stack aligned so they can avoid pushing one register. However, because regular functions might expect an aligned stack, the interrupt controller will forcibly re-align the stack when an interrupt happens in such a leaf function (controlled by the STKALIGN flag, defaults to on). This means that stack size calculation (as used in TinyGo) needs to make sure this extra space for stack re-alignment is available. This commit fixes this by aligning the stack size that will be used for new goroutines. Additionally, it increases the stack canary size from 4 to 8 bytes, to keep the stack aligned. This is not strictly necessary but is required by the AAPCS so let's do it anyway just to be sure. --- builder/build.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/builder/build.go b/builder/build.go index 8a433ca24..f17d26c72 100644 --- a/builder/build.go +++ b/builder/build.go @@ -953,15 +953,19 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map if fn.stackSizeType == stacksize.Bounded { stackSize := uint32(fn.stackSize) - // Adding 4 for the stack canary. Even though the size may be - // automatically determined, stack overflow checking is still - // important as the stack size cannot be determined for all - // goroutines. - stackSize += 4 - // Add stack size used by interrupts. switch fileHeader.Machine { case elf.EM_ARM: + if stackSize%8 != 0 { + // If the stack isn't a multiple of 8, it means the leaf + // function with the biggest stack depth doesn't have an aligned + // stack. If the STKALIGN flag is set (which it is by default) + // the interrupt controller will forcibly align the stack before + // storing in-use registers. This will thus overwrite one word + // past the end of the stack (off-by-one). + stackSize += 4 + } + // On Cortex-M (assumed here), this stack size is 8 words or 32 // bytes. This is only to store the registers that the interrupt // may modify, the interrupt will switch to the interrupt stack @@ -969,6 +973,14 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map // Some background: // https://interrupt.memfault.com/blog/cortex-m-rtos-context-switching stackSize += 32 + + // Adding 4 for the stack canary, and another 4 to keep the + // stack aligned. Even though the size may be automatically + // determined, stack overflow checking is still important as the + // stack size cannot be determined for all goroutines. + stackSize += 8 + default: + return fmt.Errorf("unknown architecture: %s", fileHeader.Machine.String()) } // Finally write the stack size to the binary. From cdba4fa8ccde75839dcbbbac30ebfd727aeff909 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Thu, 8 Jul 2021 23:52:40 +0200 Subject: [PATCH 18/29] interp: don't ignore array indices for untyped objects This fixes https://github.com/tinygo-org/tinygo/issues/1884. My original plan to fix this was much more complicated, but then I realized that the output type doesn't matter anyway and I can simply cast the type to an *i8 and perform a GEP on that pointer. --- interp/interp.go | 2 +- interp/memory.go | 11 +++++++++++ testdata/init.go | 15 +++++++++++++++ testdata/init.txt | 2 ++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/interp/interp.go b/interp/interp.go index 8da27705f..d3976ef7f 100644 --- a/interp/interp.go +++ b/interp/interp.go @@ -15,7 +15,7 @@ import ( // package is changed in a way that affects the output so that cached package // builds will be invalidated. // This version is independent of the TinyGo version number. -const Version = 1 +const Version = 2 // last change: fix GEP on untyped pointers // Enable extra checks, which should be disabled by default. // This may help track down bugs by adding a few more sanity checks. diff --git a/interp/memory.go b/interp/memory.go index ccd98c8b0..53b798a3e 100644 --- a/interp/memory.go +++ b/interp/memory.go @@ -572,6 +572,17 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val } if llvmType.IsNil() { + if v.offset() != 0 { + // If there is an offset, make sure to use a GEP to index into the + // pointer. Because there is no expected type, we use whatever is + // most convenient: an *i8 type. It is trivial to index byte-wise. + if llvmValue.Type() != mem.r.i8ptrType { + llvmValue = llvm.ConstBitCast(llvmValue, mem.r.i8ptrType) + } + llvmValue = llvm.ConstInBoundsGEP(llvmValue, []llvm.Value{ + llvm.ConstInt(llvmValue.Type().Context().Int32Type(), uint64(v.offset()), false), + }) + } return llvmValue, nil } diff --git a/testdata/init.go b/testdata/init.go index 6e7d9e7ba..5cb7f2d28 100644 --- a/testdata/init.go +++ b/testdata/init.go @@ -13,6 +13,8 @@ func main() { println("v5:", len(v5), v5 == nil) println("v6:", v6) println("v7:", cap(v7), string(v7)) + println("v8:", v8) + println("v9:", len(v9), v9[0], v9[1], v9[2]) println(uint8SliceSrc[0]) println(uint8SliceDst[0]) @@ -35,6 +37,8 @@ var ( v5 = map[string]int{} v6 = float64(v1) < 2.6 v7 = []byte("foo") + v8 string + v9 []int uint8SliceSrc = []uint8{3, 100} uint8SliceDst []uint8 @@ -48,4 +52,15 @@ func init() { intSliceDst = make([]int16, len(intSliceSrc)) copy(intSliceDst, intSliceSrc) + + v8 = sliceString("foobarbaz", 3, 8) + v9 = sliceSlice([]int{0, 1, 2, 3, 4, 5}, 2, 5) +} + +func sliceString(s string, start, end int) string { + return s[start:end] +} + +func sliceSlice(s []int, start, end int) []int { + return s[start:end] } diff --git a/testdata/init.txt b/testdata/init.txt index c421c1151..a6b9736c5 100644 --- a/testdata/init.txt +++ b/testdata/init.txt @@ -7,6 +7,8 @@ v4: 0 true v5: 0 false v6: false v7: 3 foo +v8: barba +v9: 3 2 3 4 3 3 5 From 8cc7c6d57202575e2ac4fc5024830333308efee9 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 14 Jul 2021 15:44:00 +0200 Subject: [PATCH 19/29] interp: populate Inst field in interp.Error It is used in the main package but wasn't actually set anywhere. --- interp/errors.go | 1 + 1 file changed, 1 insertion(+) diff --git a/interp/errors.go b/interp/errors.go index 48cf85df0..c90de3329 100644 --- a/interp/errors.go +++ b/interp/errors.go @@ -57,6 +57,7 @@ func (r *runner) errorAt(inst instruction, err error) *Error { pos := getPosition(inst.llvmInst) return &Error{ ImportPath: r.pkgName, + Inst: inst.llvmInst, Pos: pos, Err: err, Traceback: []ErrorLine{{pos, inst.llvmInst}}, From 607d8242111560233ffd54eda461a43cc9c4760b Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 14 Jul 2021 15:45:11 +0200 Subject: [PATCH 20/29] interp: keep reverted package initializers in order Previously, a package initializer that could not be reverted correctly would be called at runtime. But the initializer would be called in the wrong order: after later packages are initialized. This commit fixes this oversight and adds a test to verify the new behavior. --- interp/interp.go | 4 +++- interp/interp_test.go | 1 + interp/testdata/revert.ll | 21 +++++++++++++++++++++ interp/testdata/revert.out.ll | 15 +++++++++++++++ 4 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 interp/testdata/revert.ll create mode 100644 interp/testdata/revert.out.ll diff --git a/interp/interp.go b/interp/interp.go index d3976ef7f..574fe01ab 100644 --- a/interp/interp.go +++ b/interp/interp.go @@ -110,17 +110,19 @@ func Run(mod llvm.Module, debug bool) error { fmt.Fprintln(os.Stderr, "call:", fn.Name()) } _, mem, callErr := r.run(r.getFunction(fn), nil, nil, " ") + call.EraseFromParentAsInstruction() if callErr != nil { if isRecoverableError(callErr.Err) { if r.debug { fmt.Fprintln(os.Stderr, "not interpreting", r.pkgName, "because of error:", callErr.Error()) } mem.revert() + i8undef := llvm.Undef(r.i8ptrType) + r.builder.CreateCall(fn, []llvm.Value{i8undef, i8undef}, "") continue } return callErr } - call.EraseFromParentAsInstruction() for index, obj := range mem.objects { r.objects[index] = obj } diff --git a/interp/interp_test.go b/interp/interp_test.go index 50af8af60..9702cb837 100644 --- a/interp/interp_test.go +++ b/interp/interp_test.go @@ -17,6 +17,7 @@ func TestInterp(t *testing.T) { "slice-copy", "consteval", "interface", + "revert", } { name := name // make tc local to this closure t.Run(name, func(t *testing.T) { diff --git a/interp/testdata/revert.ll b/interp/testdata/revert.ll new file mode 100644 index 000000000..49354ce9c --- /dev/null +++ b/interp/testdata/revert.ll @@ -0,0 +1,21 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64--linux" + +declare void @externalCall(i64) + +define void @runtime.initAll() unnamed_addr { +entry: + call void @foo.init(i8* undef, i8* undef) + call void @main.init(i8* undef, i8* undef) + ret void +} + +define internal void @foo.init(i8* %context, i8* %parentHandle) unnamed_addr { + unreachable ; this triggers a revert of @foo.init. +} + +define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr { +entry: + call void @externalCall(i64 3) + ret void +} diff --git a/interp/testdata/revert.out.ll b/interp/testdata/revert.out.ll new file mode 100644 index 000000000..7309439f2 --- /dev/null +++ b/interp/testdata/revert.out.ll @@ -0,0 +1,15 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64--linux" + +declare void @externalCall(i64) local_unnamed_addr + +define void @runtime.initAll() unnamed_addr { +entry: + call fastcc void @foo.init(i8* undef, i8* undef) + call void @externalCall(i64 3) + ret void +} + +define internal fastcc void @foo.init(i8* %context, i8* %parentHandle) unnamed_addr { + unreachable +} From efa0410075ea492a1113224236a1210be74e1650 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Wed, 14 Jul 2021 20:10:37 +0200 Subject: [PATCH 21/29] interp: fix bug in compiler-time/run-time package initializers Make sure that if a package initializer cannot be run, later package initializers won't try to access any global variables touched by the uninterpretable package initializer. --- interp/interp.go | 23 +++++++++++++++++++++++ interp/testdata/revert.ll | 11 +++++++++++ interp/testdata/revert.out.ll | 6 ++++++ 3 files changed, 40 insertions(+) diff --git a/interp/interp.go b/interp/interp.go index 574fe01ab..cab9d9e35 100644 --- a/interp/interp.go +++ b/interp/interp.go @@ -116,9 +116,16 @@ func Run(mod llvm.Module, debug bool) error { if r.debug { fmt.Fprintln(os.Stderr, "not interpreting", r.pkgName, "because of error:", callErr.Error()) } + // Remove instructions that were created as part of interpreting + // the package. mem.revert() + // Create a call to the package initializer (which was + // previously deleted). i8undef := llvm.Undef(r.i8ptrType) r.builder.CreateCall(fn, []llvm.Value{i8undef, i8undef}, "") + // Make sure that any globals touched by the package + // initializer, won't be accessed by later package initializers. + r.markExternalLoad(fn) continue } return callErr @@ -272,3 +279,19 @@ func (r *runner) getFunction(llvmFn llvm.Value) *function { r.functionCache[llvmFn] = fn return fn } + +// markExternalLoad marks the given llvmValue as being loaded externally. This +// is primarily used to mark package initializers that could not be run at +// compile time. As an example, a package initialize might store to a global +// variable. Another package initializer might read from the same global +// variable. By marking this function as being run at runtime, that load +// instruction will need to be run at runtime instead of at compile time. +func (r *runner) markExternalLoad(llvmValue llvm.Value) { + mem := memoryView{r: r} + mem.markExternalLoad(llvmValue) + for index, obj := range mem.objects { + if obj.marked > r.objects[index].marked { + r.objects[index].marked = obj.marked + } + } +} diff --git a/interp/testdata/revert.ll b/interp/testdata/revert.ll index 49354ce9c..41fb6a81e 100644 --- a/interp/testdata/revert.ll +++ b/interp/testdata/revert.ll @@ -3,17 +3,28 @@ target triple = "x86_64--linux" declare void @externalCall(i64) +@foo.knownAtRuntime = global i64 0 +@bar.knownAtRuntime = global i64 0 + define void @runtime.initAll() unnamed_addr { entry: call void @foo.init(i8* undef, i8* undef) + call void @bar.init(i8* undef, i8* undef) call void @main.init(i8* undef, i8* undef) ret void } define internal void @foo.init(i8* %context, i8* %parentHandle) unnamed_addr { + store i64 5, i64* @foo.knownAtRuntime unreachable ; this triggers a revert of @foo.init. } +define internal void @bar.init(i8* %context, i8* %parentHandle) unnamed_addr { + %val = load i64, i64* @foo.knownAtRuntime + store i64 %val, i64* @bar.knownAtRuntime + ret void +} + define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr { entry: call void @externalCall(i64 3) diff --git a/interp/testdata/revert.out.ll b/interp/testdata/revert.out.ll index 7309439f2..4f38e4c41 100644 --- a/interp/testdata/revert.out.ll +++ b/interp/testdata/revert.out.ll @@ -1,15 +1,21 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64--linux" +@foo.knownAtRuntime = local_unnamed_addr global i64 0 +@bar.knownAtRuntime = local_unnamed_addr global i64 0 + declare void @externalCall(i64) local_unnamed_addr define void @runtime.initAll() unnamed_addr { entry: call fastcc void @foo.init(i8* undef, i8* undef) + %val = load i64, i64* @foo.knownAtRuntime, align 8 + store i64 %val, i64* @bar.knownAtRuntime, align 8 call void @externalCall(i64 3) ret void } define internal fastcc void @foo.init(i8* %context, i8* %parentHandle) unnamed_addr { + store i64 5, i64* @foo.knownAtRuntime, align 8 unreachable } From 00ea0b1d57a7ae775df81d0913af7905f7d76e32 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sat, 10 Jul 2021 23:15:58 +0200 Subject: [PATCH 22/29] build: list libraries at the end of the linker command Static libraries should be added at the end of the linker command, after all object files. If that isn't done, that's _usually_ not a problem, unless there are duplicate symbols. In that case, weird dependency issues can arise. To solve that, object files (that may include symbols to override symbols in the library) should be listed first on the command line and then the static libraries should be listed. This fixes an issue with overriding some symbols in wasi-libc. --- builder/build.go | 50 +++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/builder/build.go b/builder/build.go index f17d26c72..5c38433bd 100644 --- a/builder/build.go +++ b/builder/build.go @@ -470,33 +470,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil linkerDependencies = append(linkerDependencies, job) } - // Add libc dependency if needed. - root := goenv.Get("TINYGOROOT") - switch config.Target.Libc { - case "picolibc": - job, err := Picolibc.load(config.Triple(), config.CPU(), dir) - if err != nil { - return err - } - // The library needs to be compiled (cache miss). - jobs = append(jobs, job.dependencies...) - jobs = append(jobs, job) - linkerDependencies = append(linkerDependencies, job) - case "wasi-libc": - path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a") - if _, err := os.Stat(path); os.IsNotExist(err) { - return errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?") - } - ldflags = append(ldflags, path) - case "": - // no library specified, so nothing to do - default: - return fmt.Errorf("unknown libc: %s", config.Target.Libc) - } - // Add jobs to compile extra files. These files are in C or assembly and // contain things like the interrupt vector table and low level operations // such as stack switching. + root := goenv.Get("TINYGOROOT") for _, path := range config.ExtraFiles() { abspath := filepath.Join(root, path) job := &compileJob{ @@ -537,6 +514,31 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil ldflags = append(ldflags, lprogram.LDFlags...) } + // Add libc dependency if needed. + switch config.Target.Libc { + case "picolibc": + job, err := Picolibc.load(config.Triple(), config.CPU(), dir) + if err != nil { + return err + } + // The library needs to be compiled (cache miss). + jobs = append(jobs, job.dependencies...) + jobs = append(jobs, job) + linkerDependencies = append(linkerDependencies, job) + case "wasi-libc": + path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a") + if _, err := os.Stat(path); os.IsNotExist(err) { + return errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?") + } + job := dummyCompileJob(path) + jobs = append(jobs, job) + linkerDependencies = append(linkerDependencies, job) + case "": + // no library specified, so nothing to do + default: + return fmt.Errorf("unknown libc: %s", config.Target.Libc) + } + // Create a linker job, which links all object files together and does some // extra stuff that can only be done after linking. jobs = append(jobs, &compileJob{ From b40703e9860ef5872bc57fff0cbb91ee6c964208 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sat, 10 Jul 2021 12:17:43 +0200 Subject: [PATCH 23/29] wasm: override dlmalloc heap implementation from wasi-libc These two heaps conflict with each other, so that if any function uses the dlmalloc heap implementation it will eventually result in memory corruption. This commit fixes this by implementing all heap-related functions. This overrides the functions that are implemented in wasi-libc. That's why all of them are implemented (even if they just panic): to make sure no program accidentally uses the wrong one. --- main_test.go | 29 ++++++++++---------- src/runtime/arch_tinygowasm.go | 48 ++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 15 deletions(-) diff --git a/main_test.go b/main_test.go index 51fd21fd2..9ed0c6c54 100644 --- a/main_test.go +++ b/main_test.go @@ -125,7 +125,7 @@ func TestCompiler(t *testing.T) { // Test with few optimizations enabled (no inlining, etc). t.Run("opt=1", func(t *testing.T) { t.Parallel() - runTestWithConfig("stdlib.go", "", t, &compileopts.Options{ + runTestWithConfig("stdlib.go", "", t, compileopts.Options{ Opt: "1", }, nil, nil) }) @@ -134,15 +134,14 @@ func TestCompiler(t *testing.T) { // TODO: fix this for stdlib.go, which currently fails. t.Run("opt=0", func(t *testing.T) { t.Parallel() - runTestWithConfig("print.go", "", t, &compileopts.Options{ + runTestWithConfig("print.go", "", t, compileopts.Options{ Opt: "0", }, nil, nil) }) t.Run("ldflags", func(t *testing.T) { t.Parallel() - runTestWithConfig("ldflags.go", "", t, &compileopts.Options{ - Opt: "z", + runTestWithConfig("ldflags.go", "", t, compileopts.Options{ GlobalValues: map[string]map[string]string{ "main": { "someGlobal": "foobar", @@ -188,20 +187,20 @@ func runBuild(src, out string, opts *compileopts.Options) error { } func runTest(name, target string, t *testing.T, cmdArgs, environmentVars []string) { - options := &compileopts.Options{ - Target: target, - Opt: "z", - PrintIR: false, - DumpSSA: false, - VerifyIR: true, - Debug: true, - PrintSizes: "", - WasmAbi: "", + options := compileopts.Options{ + Target: target, } runTestWithConfig(name, target, t, options, cmdArgs, environmentVars) } -func runTestWithConfig(name, target string, t *testing.T, options *compileopts.Options, cmdArgs, environmentVars []string) { +func runTestWithConfig(name, target string, t *testing.T, options compileopts.Options, cmdArgs, environmentVars []string) { + // Set default config. + options.Debug = true + options.VerifyIR = true + if options.Opt == "" { + options.Opt = "z" + } + // Get the expected output for this test. // Note: not using filepath.Join as it strips the path separator at the end // of the path. @@ -230,7 +229,7 @@ func runTestWithConfig(name, target string, t *testing.T, options *compileopts.O // Build the test binary. binary := filepath.Join(tmpdir, "test") - err = runBuild("./"+path, binary, options) + err = runBuild("./"+path, binary, &options) if err != nil { printCompilerError(t.Log, err) t.Fail() diff --git a/src/runtime/arch_tinygowasm.go b/src/runtime/arch_tinygowasm.go index 0ee3afd3b..753591e9c 100644 --- a/src/runtime/arch_tinygowasm.go +++ b/src/runtime/arch_tinygowasm.go @@ -55,3 +55,51 @@ func growHeap() bool { // Heap has grown successfully. return true } + +// The below functions override the default allocator of wasi-libc. +// Most functions are defined but unimplemented to make sure that if there is +// any code using them, they will get an error instead of (incorrectly) using +// the wasi-libc dlmalloc heap implementation instead. If they are needed by any +// program, they can certainly be implemented. + +//export malloc +func libc_malloc(size uintptr) unsafe.Pointer { + return alloc(size) +} + +//export free +func libc_free(ptr unsafe.Pointer) { + free(ptr) +} + +//export calloc +func libc_calloc(nmemb, size uintptr) unsafe.Pointer { + // Note: we could be even more correct here and check that nmemb * size + // doesn't overflow. However the current implementation should normally work + // fine. + return alloc(nmemb * size) +} + +//export realloc +func libc_realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer { + runtimePanic("unimplemented: realloc") + return nil +} + +//export posix_memalign +func libc_posix_memalign(memptr *unsafe.Pointer, alignment, size uintptr) int { + runtimePanic("unimplemented: posix_memalign") + return 0 +} + +//export aligned_alloc +func libc_aligned_alloc(alignment, bytes uintptr) unsafe.Pointer { + runtimePanic("unimplemented: aligned_alloc") + return nil +} + +//export malloc_usable_size +func libc_malloc_usable_size(ptr unsafe.Pointer) uintptr { + runtimePanic("unimplemented: malloc_usable_size") + return 0 +} From 73cf187552c4a104f986a209c6813a5eb58ac5f7 Mon Sep 17 00:00:00 2001 From: sago35 Date: Mon, 28 Jun 2021 16:09:02 +0900 Subject: [PATCH 24/29] machine/feather-nrf52: fix pin definition of uart --- src/machine/board_feather-nrf52840-sense.go | 8 ++++++-- src/machine/board_feather-nrf52840.go | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/machine/board_feather-nrf52840-sense.go b/src/machine/board_feather-nrf52840-sense.go index 4d8804f73..8a4f71446 100644 --- a/src/machine/board_feather-nrf52840-sense.go +++ b/src/machine/board_feather-nrf52840-sense.go @@ -72,8 +72,8 @@ const ( // UART0 pins (logical UART1) const ( - UART_RX_PIN = D0 - UART_TX_PIN = D1 + UART_RX_PIN = D1 + UART_TX_PIN = D0 ) // I2C pins @@ -99,3 +99,7 @@ var ( usb_VID uint16 = 0x239A usb_PID uint16 = 0x8088 ) + +var ( + DefaultUART = UART0 +) diff --git a/src/machine/board_feather-nrf52840.go b/src/machine/board_feather-nrf52840.go index 488d9608b..e433e1037 100644 --- a/src/machine/board_feather-nrf52840.go +++ b/src/machine/board_feather-nrf52840.go @@ -72,8 +72,8 @@ const ( // UART0 pins (logical UART1) const ( - UART_RX_PIN = D0 - UART_TX_PIN = D1 + UART_RX_PIN = D1 + UART_TX_PIN = D0 ) // I2C pins @@ -99,3 +99,7 @@ var ( usb_VID uint16 = 0x239A usb_PID uint16 = 0x802A ) + +var ( + DefaultUART = UART0 +) From 03481789b0bbc83b9381b3aec32c87965f8158c2 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 20 Jul 2021 13:21:25 +0200 Subject: [PATCH 25/29] runtime: fix time base for time.Now() This function previously returned the atomic time, that isn't affected by system time changes but also has a time base at some arbitrary time in the past. This makes sense for baremetal platforms (which typically don't know the wall time) but it gives surprising results on Linux and macOS: time.Now() usually returns a time somewhere near the start of 1970. This commit fixes this by obtaining both time values: the monotonic time and the wall clock time. This is also how the Go runtime implements the time.now function. --- src/runtime/baremetal.go | 21 +++++++++++++++++++++ src/runtime/os_darwin.go | 6 ++++++ src/runtime/os_linux.go | 6 ++++++ src/runtime/runtime.go | 21 --------------------- src/runtime/runtime_tinygowasm.go | 8 ++++++++ src/runtime/runtime_unix.go | 24 +++++++++++++++++------- 6 files changed, 58 insertions(+), 28 deletions(-) diff --git a/src/runtime/baremetal.go b/src/runtime/baremetal.go index ce69e338d..5abd13710 100644 --- a/src/runtime/baremetal.go +++ b/src/runtime/baremetal.go @@ -52,3 +52,24 @@ func syscall_Exit(code int) { } const baremetal = true + +// timeOffset is how long the monotonic clock started after the Unix epoch. It +// should be a positive integer under normal operation or zero when it has not +// been set. +var timeOffset int64 + +//go:linkname now time.now +func now() (sec int64, nsec int32, mono int64) { + mono = nanotime() + sec = (mono + timeOffset) / (1000 * 1000 * 1000) + nsec = int32((mono + timeOffset) - sec*(1000*1000*1000)) + return +} + +// AdjustTimeOffset adds the given offset to the built-in time offset. A +// positive value adds to the time (skipping some time), a negative value moves +// the clock into the past. +func AdjustTimeOffset(offset int64) { + // TODO: do this atomically? + timeOffset += offset +} diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go index ac31b67da..be8789098 100644 --- a/src/runtime/os_darwin.go +++ b/src/runtime/os_darwin.go @@ -11,3 +11,9 @@ const ( flag_MAP_PRIVATE = 0x2 flag_MAP_ANONYMOUS = 0x1000 // MAP_ANON ) + +// Source: https://opensource.apple.com/source/Libc/Libc-1439.100.3/include/time.h.auto.html +const ( + clock_REALTIME = 0 + clock_MONOTONIC_RAW = 4 +) diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go index 7613134e3..aa056173b 100644 --- a/src/runtime/os_linux.go +++ b/src/runtime/os_linux.go @@ -11,3 +11,9 @@ const ( flag_MAP_PRIVATE = 0x2 flag_MAP_ANONYMOUS = 0x20 ) + +// Source: https://github.com/torvalds/linux/blob/master/include/uapi/linux/time.h +const ( + clock_REALTIME = 0 + clock_MONOTONIC_RAW = 4 +) diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go index 7b1b4f5ae..55102411b 100644 --- a/src/runtime/runtime.go +++ b/src/runtime/runtime.go @@ -68,27 +68,6 @@ func nanotime() int64 { return ticksToNanoseconds(ticks()) } -// timeOffset is how long the monotonic clock started after the Unix epoch. It -// should be a positive integer under normal operation or zero when it has not -// been set. -var timeOffset int64 - -//go:linkname now time.now -func now() (sec int64, nsec int32, mono int64) { - mono = nanotime() - sec = (mono + timeOffset) / (1000 * 1000 * 1000) - nsec = int32((mono + timeOffset) - sec*(1000*1000*1000)) - return -} - -// AdjustTimeOffset adds the given offset to the built-in time offset. A -// positive value adds to the time (skipping some time), a negative value moves -// the clock into the past. -func AdjustTimeOffset(offset int64) { - // TODO: do this atomically? - timeOffset += offset -} - // Copied from the Go runtime source code. //go:linkname os_sigpipe os.sigpipe func os_sigpipe() { diff --git a/src/runtime/runtime_tinygowasm.go b/src/runtime/runtime_tinygowasm.go index 989fbb803..80eaa8d3e 100644 --- a/src/runtime/runtime_tinygowasm.go +++ b/src/runtime/runtime_tinygowasm.go @@ -50,6 +50,14 @@ func putchar(c byte) { } } +//go:linkname now time.now +func now() (sec int64, nsec int32, mono int64) { + mono = nanotime() + sec = mono / (1000 * 1000 * 1000) + nsec = int32(mono - sec*(1000*1000*1000)) + return +} + // Abort executes the wasm 'unreachable' instruction. func abort() { trap() diff --git a/src/runtime/runtime_unix.go b/src/runtime/runtime_unix.go index c185c4ab7..464d8dfe5 100644 --- a/src/runtime/runtime_unix.go +++ b/src/runtime/runtime_unix.go @@ -38,8 +38,6 @@ type timespec struct { tv_nsec int // long: on Linux and macOS, follows the platform bitness } -const CLOCK_MONOTONIC_RAW = 4 - var stackTop uintptr func postinit() {} @@ -138,19 +136,31 @@ func sleepTicks(d timeUnit) { usleep(uint(d) / 1000) } -// Return monotonic time in nanoseconds. -// -// TODO: noescape -func monotime() uint64 { +func getTime(clock int32) uint64 { ts := timespec{} - clock_gettime(CLOCK_MONOTONIC_RAW, &ts) + clock_gettime(clock, &ts) return uint64(ts.tv_sec)*1000*1000*1000 + uint64(ts.tv_nsec) } +// Return monotonic time in nanoseconds. +func monotime() uint64 { + return getTime(clock_MONOTONIC_RAW) +} + func ticks() timeUnit { return timeUnit(monotime()) } +//go:linkname now time.now +func now() (sec int64, nsec int32, mono int64) { + ts := timespec{} + clock_gettime(clock_REALTIME, &ts) + sec = int64(ts.tv_sec) + nsec = int32(ts.tv_nsec) + mono = nanotime() + return +} + //go:linkname syscall_Exit syscall.Exit func syscall_Exit(code int) { exit(code) From e834d7887143fc8da542d3d29907e8db7a5b9bb2 Mon Sep 17 00:00:00 2001 From: "Federico G. Schwindt" Date: Thu, 15 Jul 2021 19:14:49 +0100 Subject: [PATCH 26/29] Fix undefined symbols error Currently TinyGo does not process SFiles (assembly files), which are needed by math/big. Add math_big_pure_go to the build tags to unbreak it. --- compileopts/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compileopts/config.go b/compileopts/config.go index a60f778e0..36782506d 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -55,7 +55,7 @@ func (c *Config) GOARCH() string { // BuildTags returns the complete list of build tags used during this build. func (c *Config) BuildTags() []string { - tags := append(c.Target.BuildTags, []string{"tinygo", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...) + tags := append(c.Target.BuildTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...) for i := 1; i <= c.GoMinorVersion; i++ { tags = append(tags, fmt.Sprintf("go1.%d", i)) } From 65c1978965bc2f00d07765978f977617ba40b28f Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sun, 25 Jul 2021 14:30:16 +0200 Subject: [PATCH 27/29] wasm: align heap to 16 bytes This commit fixes two things: * It changes the alignment to 16 bytes (from 4), to match max_align_t in C. * It manually aligns heapStart on WebAssembly, to work around a bug in wasm-ld with --stack-first (see https://reviews.llvm.org/D106499). --- src/runtime/arch_tinygowasm.go | 6 ++++-- src/runtime/gc_conservative.go | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/runtime/arch_tinygowasm.go b/src/runtime/arch_tinygowasm.go index 753591e9c..a19a14487 100644 --- a/src/runtime/arch_tinygowasm.go +++ b/src/runtime/arch_tinygowasm.go @@ -32,9 +32,11 @@ var ( const wasmPageSize = 64 * 1024 -// Align on word boundary. func align(ptr uintptr) uintptr { - return (ptr + 3) &^ 3 + // Align to 16, which is the alignment of max_align_t: + // https://godbolt.org/z/dYqTsWrGq + const heapAlign = 16 + return (ptr + heapAlign - 1) &^ (heapAlign - 1) } func getCurrentStackPointer() uintptr diff --git a/src/runtime/gc_conservative.go b/src/runtime/gc_conservative.go index e96825922..67fbfdb2c 100644 --- a/src/runtime/gc_conservative.go +++ b/src/runtime/gc_conservative.go @@ -228,6 +228,14 @@ func setHeapEnd(newHeapEnd uintptr) { // This function can be called again when the heap size increases. The caller is // responsible for copying the metadata to the new location. func calculateHeapAddresses() { + if GOARCH == "wasm" { + // This is a workaround for a bug in wasm-ld: wasm-ld doesn't always + // align __heap_base and when this memory is shared through an API, it + // might result in unaligned memory. For details, see: + // https://reviews.llvm.org/D106499 + // It should be removed once we switch to LLVM 13, where this is fixed. + heapStart = align(heapStart) + } totalSize := heapEnd - heapStart // Allocate some memory to keep 2 bits of information about every block. From 7434e5a2c7110e512baa93d747ce47d5b4798446 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 13 Jul 2021 16:59:43 +0200 Subject: [PATCH 28/29] main: strip debug information at link time instead of at compile time Stripping debug information at link time also allows relocation compression (aka linker relaxations). Keeping debug information at compile time and optionally stripping it at link time has some advantages: * Automatic stack sizes on Cortex-M rely on the presence of debug information. * Some parts of the compiler now rely on the presence of debug information for proper diagnostics. * It works better with the cache: there is no distinction between debug and no-debug builds. * It makes it easier (or possible at all) to enable debug information in the wasi-libc library without big downsides. --- builder/build.go | 35 ++++++++++++++++++++++++++++++++++- compileopts/config.go | 10 +++++----- main.go | 2 +- 3 files changed, 40 insertions(+), 7 deletions(-) diff --git a/builder/build.go b/builder/build.go index 5c38433bd..c1fd78e3f 100644 --- a/builder/build.go +++ b/builder/build.go @@ -100,7 +100,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil AutomaticStackSize: config.AutomaticStackSize(), DefaultStackSize: config.Target.DefaultStackSize, NeedsStackObjects: config.NeedsStackObjects(), - Debug: config.Debug(), + Debug: true, LLVMFeatures: config.LLVMFeatures(), } @@ -539,6 +539,39 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil return fmt.Errorf("unknown libc: %s", config.Target.Libc) } + // Strip debug information with -no-debug. + if !config.Debug() { + for _, tag := range config.BuildTags() { + if tag == "baremetal" { + // Don't use -no-debug on baremetal targets. It makes no sense: + // the debug information isn't flashed to the device anyway. + return fmt.Errorf("stripping debug information is unnecessary for baremetal targets") + } + } + if config.Target.Linker == "wasm-ld" { + // Don't just strip debug information, also compress relocations + // while we're at it. Relocations can only be compressed when debug + // information is stripped. + ldflags = append(ldflags, "--strip-debug", "--compress-relocations") + } else { + switch config.GOOS() { + case "linux": + // Either real linux or an embedded system (like AVR) that + // pretends to be Linux. It's a ELF linker wrapped by GCC in any + // case. + ldflags = append(ldflags, "-Wl,--strip-debug") + case "darwin": + // MacOS (darwin) doesn't have a linker flag to strip debug + // information. Apple expects you to use the strip command + // instead. + return errors.New("cannot remove debug information: MacOS doesn't suppor this linker flag") + default: + // Other OSes may have different flags. + return errors.New("cannot remove debug information: unknown OS: " + config.GOOS()) + } + } + } + // Create a linker job, which links all object files together and does some // extra stuff that can only be done after linking. jobs = append(jobs, &compileJob{ diff --git a/compileopts/config.go b/compileopts/config.go index 36782506d..f2ba28578 100644 --- a/compileopts/config.go +++ b/compileopts/config.go @@ -209,9 +209,8 @@ func (c *Config) CFlags() []string { cflags = append(cflags, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include")) cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include")) } - if c.Debug() { - cflags = append(cflags, "-g") - } + // Always emit debug information. It is optionally stripped at link time. + cflags = append(cflags, "-g") return cflags } @@ -250,8 +249,9 @@ func (c *Config) VerifyIR() bool { return c.Options.VerifyIR } -// Debug returns whether to add debug symbols to the IR, for debugging with GDB -// and similar. +// Debug returns whether debug (DWARF) information should be retained by the +// linker. By default, debug information is retained but it can be removed with +// the -no-debug flag. func (c *Config) Debug() bool { return c.Options.Debug } diff --git a/main.go b/main.go index 7c3ee96df..c9fd0c042 100644 --- a/main.go +++ b/main.go @@ -1019,7 +1019,7 @@ func main() { printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines") printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed") printCommands := flag.Bool("x", false, "Print commands") - nodebug := flag.Bool("no-debug", false, "disable DWARF debug symbol generation") + nodebug := flag.Bool("no-debug", false, "strip debug information") ocdCommandsString := flag.String("ocd-commands", "", "OpenOCD commands, overriding target spec (can specify multiple separated by commas)") ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug") port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)") From 98e70c9b196742e37f7da3ca0e78b4f63738da8e Mon Sep 17 00:00:00 2001 From: soypat Date: Fri, 9 Jul 2021 14:40:21 -0300 Subject: [PATCH 29/29] machine/rp2040: add SPI support spi working with loopback SPI working apply @deadprogram's suggestions consolidate SPI board pin naming fix up SPI configuration add feather-rp2040 SPI pins add arduino connect SPI pins add SPI handle variables --- src/machine/board_feather_rp2040.go | 17 ++ src/machine/board_nano-rp2040.go | 7 +- src/machine/board_pico.go | 17 ++ src/machine/machine_rp2040_gpio.go | 3 + src/machine/machine_rp2040_spi.go | 361 ++++++++++++++++++++++++++++ 5 files changed, 404 insertions(+), 1 deletion(-) create mode 100644 src/machine/machine_rp2040_spi.go diff --git a/src/machine/board_feather_rp2040.go b/src/machine/board_feather_rp2040.go index 7894c5cff..4be1b4938 100644 --- a/src/machine/board_feather_rp2040.go +++ b/src/machine/board_feather_rp2040.go @@ -8,3 +8,20 @@ const ( // Onboard crystal oscillator frequency, in MHz. xoscFreq = 12 // MHz ) + +// SPI default pins +const ( + // Default Serial Clock Bus 0 for SPI communications + SPI0_SCK_PIN = GPIO18 + // Default Serial Out Bus 0 for SPI communications + SPI0_SDO_PIN = GPIO19 // Tx + // Default Serial In Bus 0 for SPI communications + SPI0_SDI_PIN = GPIO20 // Rx + + // Default Serial Clock Bus 1 for SPI communications + SPI1_SCK_PIN = GPIO10 + // Default Serial Out Bus 1 for SPI communications + SPI1_SDO_PIN = GPIO11 // Tx + // Default Serial In Bus 1 for SPI communications + SPI1_SDI_PIN = GPIO12 // Rx +) diff --git a/src/machine/board_nano-rp2040.go b/src/machine/board_nano-rp2040.go index ca85596a7..3db965a79 100644 --- a/src/machine/board_nano-rp2040.go +++ b/src/machine/board_nano-rp2040.go @@ -53,11 +53,16 @@ const ( SCL_PIN Pin = GPIO13 ) -// SPI pins +// SPI pins. SPI1 not available on Nano RP2040 Connect. const ( SPI0_SCK_PIN Pin = GPIO6 SPI0_SDO_PIN Pin = GPIO7 SPI0_SDI_PIN Pin = GPIO4 + + // GPIO22 does not have SPI functionality so we set it to avoid interfering with NINA. + SPI1_SCK_PIN Pin = GPIO22 + SPI1_SDO_PIN Pin = GPIO22 + SPI1_SDI_PIN Pin = GPIO22 ) // NINA-W102 Pins diff --git a/src/machine/board_pico.go b/src/machine/board_pico.go index 3a4d67b45..961c923cb 100644 --- a/src/machine/board_pico.go +++ b/src/machine/board_pico.go @@ -37,3 +37,20 @@ const ( // Onboard crystal oscillator frequency, in MHz. xoscFreq = 12 // MHz ) + +// SPI default pins +const ( + // Default Serial Clock Bus 0 for SPI communications + SPI0_SCK_PIN = GPIO18 + // Default Serial Out Bus 0 for SPI communications + SPI0_SDO_PIN = GPIO19 // Tx + // Default Serial In Bus 0 for SPI communications + SPI0_SDI_PIN = GPIO16 // Rx + + // Default Serial Clock Bus 1 for SPI communications + SPI1_SCK_PIN = GPIO10 + // Default Serial Out Bus 1 for SPI communications + SPI1_SDO_PIN = GPIO11 // Tx + // Default Serial In Bus 1 for SPI communications + SPI1_SDI_PIN = GPIO12 // Rx +) diff --git a/src/machine/machine_rp2040_gpio.go b/src/machine/machine_rp2040_gpio.go index b994988e4..e5394685d 100644 --- a/src/machine/machine_rp2040_gpio.go +++ b/src/machine/machine_rp2040_gpio.go @@ -68,6 +68,7 @@ const ( PinInputPullup PinAnalog PinUART + PinSPI ) // set drives the pin high @@ -155,6 +156,8 @@ func (p Pin) Configure(config PinConfig) { p.pulloff() case PinUART: p.setFunc(fnUART) + case PinSPI: + p.setFunc(fnSPI) } } diff --git a/src/machine/machine_rp2040_spi.go b/src/machine/machine_rp2040_spi.go new file mode 100644 index 000000000..ac2bcabe6 --- /dev/null +++ b/src/machine/machine_rp2040_spi.go @@ -0,0 +1,361 @@ +// +build rp2040 + +package machine + +import ( + "device/rp" + "errors" +) + +// SPI on the RP2040 +var ( + SPI0 = &_SPI0 + _SPI0 = SPI{ + Bus: rp.SPI0, + } + SPI1 = &_SPI1 + _SPI1 = SPI{ + Bus: rp.SPI1, + } +) + +// SPIConfig is used to store config info for SPI. +type SPIConfig struct { + Frequency uint32 + // LSB not supported on rp2040. + LSBFirst bool + // Mode's two most LSB are CPOL and CPHA. i.e. Mode==2 (0b10) is CPOL=1, CPHA=0 + Mode uint8 + // Number of data bits per transfer. Valid values 4..16. Default and recommended is 8. + DataBits uint8 + // Serial clock pin + SCK Pin + // TX or Serial Data Out (MOSI if rp2040 is master) + SDO Pin + // RX or Serial Data In (MISO if rp2040 is master) + SDI Pin +} + +var ( + ErrLSBNotSupported = errors.New("SPI LSB unsupported on PL022") + ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size") + ErrSPITimeout = errors.New("SPI timeout") + ErrSPIBaud = errors.New("SPI baud too low or above 66.5Mhz") +) + +type SPI struct { + Bus *rp.SPI0_Type +} + +// time to wait on a transaction before dropping. Unit in Microseconds for compatibility with ticks(). +const _SPITimeout = 10 * 1000 // 10 ms + +// Tx handles read/write operation for SPI interface. Since SPI is a syncronous write/read +// interface, there must always be the same number of bytes written as bytes read. +// The Tx method knows about this, and offers a few different ways of calling it. +// +// This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer. +// Note that the tx and rx buffers must be the same size: +// +// spi.Tx(tx, rx) +// +// This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros +// until all the bytes in the command packet have been received: +// +// spi.Tx(tx, nil) +// +// This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet": +// +// spi.Tx(nil, rx) +// +// Remark: This implementation (RP2040) allows reading into buffer with a custom repeated +// value on tx. +// +// spi.Tx([]byte{0xff}, rx) // may cause unwanted heap allocations. +// +// This form sends 0xff and puts the result into rx buffer. Useful for reading from SD cards +// which require 0xff input on SI. +func (spi SPI) Tx(w, r []byte) (err error) { + switch { + case w == nil: + // read only, so write zero and read a result. + err = spi.rx(r, 0) + case r == nil: + // write only + err = spi.tx(w) + case len(w) == 1 && len(r) > 1: + // Read with custom repeated value. + err = spi.rx(r, w[0]) + default: + // write/read + err = spi.txrx(w, r) + } + return err +} + +// Write a single byte and read a single byte from TX/RX FIFO. +func (spi SPI) Transfer(w byte) (byte, error) { + var deadline = ticks() + _SPITimeout + for !spi.isWritable() { + if ticks() > deadline { + return 0, ErrSPITimeout + } + } + + spi.Bus.SSPDR.Set(uint32(w)) + + for !spi.isReadable() { + if ticks() > deadline { + return 0, ErrSPITimeout + } + } + return uint8(spi.Bus.SSPDR.Get()), nil +} + +func (spi SPI) SetBaudRate(br uint32) error { + const freqin uint32 = 125 * MHz + const maxBaud uint32 = 66.5 * MHz // max output frequency is 66.5MHz on rp2040. see Note page 527. + // Find smallest prescale value which puts output frequency in range of + // post-divide. Prescale is an even number from 2 to 254 inclusive. + var prescale, postdiv uint32 + for prescale = 2; prescale < 255; prescale += 2 { + if freqin < (prescale+2)*256*br { + break + } + } + if prescale > 254 || br > maxBaud { + return ErrSPIBaud + } + // Find largest post-divide which makes output <= baudrate. Post-divide is + // an integer in the range 1 to 256 inclusive. + for postdiv = 256; postdiv > 1; postdiv-- { + if freqin/(prescale*(postdiv-1)) > br { + break + } + } + spi.Bus.SSPCPSR.Set(prescale) + spi.Bus.SSPCR0.ReplaceBits((postdiv-1)<> rp.SPI0_SSPCR0_SCR_Pos) + 1 + return freqin / (prescale * postdiv) +} + +// Configure is intended to setup/initialize the SPI interface. +// Default baudrate of 115200 is used if Frequency == 0. Default +// word length (data bits) is 8. +// Below is a list of GPIO pins corresponding to SPI0 bus on the rp2040: +// SI : 0, 4, 17 a.k.a RX and MISO (if rp2040 is master) +// SO : 3, 7, 19 a.k.a TX and MOSI (if rp2040 is master) +// SCK: 2, 6, 18 +// SPI1 bus GPIO pins: +// SI : 8, 12 +// SO : 11, 15 +// SCK: 10, 14 +// No pin configuration is needed of SCK, SDO and SDI needed after calling Configure. +func (spi SPI) Configure(config SPIConfig) error { + const defaultBaud uint32 = 115200 + if config.SCK == 0 { + // set default pins if config zero valued or invalid clock pin supplied. + switch spi.Bus { + case rp.SPI0: + config.SCK = SPI0_SCK_PIN + config.SDO = SPI0_SDO_PIN + config.SDI = SPI0_SDI_PIN + case rp.SPI1: + config.SCK = SPI1_SCK_PIN + config.SDO = SPI1_SDO_PIN + config.SDI = SPI1_SDI_PIN + } + } + if config.DataBits < 4 || config.DataBits > 16 { + config.DataBits = 8 + } + if config.Frequency == 0 { + config.Frequency = defaultBaud + } + // SPI pin configuration + config.SCK.setFunc(fnSPI) + config.SDO.setFunc(fnSPI) + config.SDI.setFunc(fnSPI) + + return spi.initSPI(config) +} + +func (spi SPI) initSPI(config SPIConfig) (err error) { + spi.reset() + // LSB-first not supported on PL022: + if config.LSBFirst { + return ErrLSBNotSupported + } + err = spi.SetBaudRate(config.Frequency) + // Set SPI Format (CPHA and CPOL) and frame format (default is Motorola) + spi.setFormat(config.DataBits, config.Mode, rp.XIP_SSI_CTRLR0_SPI_FRF_STD) + + // Always enable DREQ signals -- harmless if DMA is not listening + spi.Bus.SSPDMACR.SetBits(rp.SPI0_SSPDMACR_TXDMAE | rp.SPI0_SSPDMACR_RXDMAE) + // Finally enable the SPI + spi.Bus.SSPCR1.SetBits(rp.SPI0_SSPCR1_SSE) + return err +} + +//go:inline +func (spi SPI) setFormat(databits, mode uint8, frameFormat uint32) { + cpha := uint32(mode) & 1 + cpol := uint32(mode>>1) & 1 + spi.Bus.SSPCR0.ReplaceBits( + (cpha< deadline { + return ErrSPITimeout + } + } + spi.Bus.SSPDR.Set(uint32(tx[i])) + } + // Drain RX FIFO, then wait for shifting to finish (which may be *after* + // TX FIFO drains), then drain RX FIFO again + for spi.isReadable() { + spi.Bus.SSPDR.Get() + } + for spi.isBusy() { + if ticks() > deadline { + return ErrSPITimeout + } + } + for spi.isReadable() { + spi.Bus.SSPDR.Get() + } + // Don't leave overrun flag set + spi.Bus.SSPICR.Set(rp.SPI0_SSPICR_RORIC) + return nil +} + +// rx reads buffer to SPI ignoring x. +// txrepeat is output repeatedly on SO as data is read in from SI. +// Generally this can be 0, but some devices require a specific value here, +// e.g. SD cards expect 0xff +func (spi SPI) rx(rx []byte, txrepeat byte) error { + var deadline = ticks() + _SPITimeout + plen := len(rx) + const fifoDepth = 8 // see txrx + var rxleft, txleft = plen, plen + for txleft != 0 || rxleft != 0 { + if txleft != 0 && spi.isWritable() && rxleft < txleft+fifoDepth { + spi.Bus.SSPDR.Set(uint32(txrepeat)) + txleft-- + } + if rxleft != 0 && spi.isReadable() { + rx[plen-rxleft] = uint8(spi.Bus.SSPDR.Get()) + rxleft-- + continue // if reading succesfully in rx there is no need to check deadline. + } + if ticks() > deadline { + return ErrSPITimeout + } + } + return nil +} + +// Write len bytes from src to SPI. Simultaneously read len bytes from SPI to dst. +// Note this function is guaranteed to exit in a known amount of time (bits sent * time per bit) +func (spi SPI) txrx(tx, rx []byte) error { + var deadline = ticks() + _SPITimeout + plen := len(tx) + if plen != len(rx) { + return ErrTxInvalidSliceSize + } + // Never have more transfers in flight than will fit into the RX FIFO, + // else FIFO will overflow if this code is heavily interrupted. + const fifoDepth = 8 + var rxleft, txleft = plen, plen + for (txleft != 0 || rxleft != 0) && ticks() <= deadline { + if txleft != 0 && spi.isWritable() && rxleft < txleft+fifoDepth { + spi.Bus.SSPDR.Set(uint32(tx[plen-txleft])) + txleft-- + } + if rxleft != 0 && spi.isReadable() { + rx[plen-rxleft] = uint8(spi.Bus.SSPDR.Get()) + rxleft-- + } + } + + if txleft != 0 || rxleft != 0 { + // Transaction ended early due to timeout + return ErrSPITimeout + } + + return nil +}