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/Makefile b/Makefile index e2981789b..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 @@ -356,7 +358,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 @@ -432,6 +438,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/README.md b/README.md index ae3a8b526..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 63 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 63 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) @@ -69,7 +70,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 +100,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/builder/build.go b/builder/build.go index 8a433ca24..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(), } @@ -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,64 @@ 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) + } + + // 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{ @@ -953,15 +988,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 +1008,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. diff --git a/compileopts/config.go b/compileopts/config.go index 821aa8313..f2ba28578 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", "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)) } @@ -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) { @@ -197,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 } @@ -238,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/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/compiler/compiler.go b/compiler/compiler.go index 925b61bf8..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() @@ -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,10 +758,13 @@ 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) + 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. @@ -1304,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/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/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/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 +} diff --git a/compiler/testdata/pragma.go b/compiler/testdata/pragma.go new file mode 100644 index 000000000..b6ebc83b2 --- /dev/null +++ b/compiler/testdata/pragma.go @@ -0,0 +1,66 @@ +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() { +} + +// 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 new file mode 100644 index 000000000..0515098c5 --- /dev/null +++ b/compiler/testdata/pragma.ll @@ -0,0 +1,59 @@ +; 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 +@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*) + +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 +} + +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/goenv/version.go b/goenv/version.go index 909f330f4..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-dev" +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. 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}}, diff --git a/interp/interp.go b/interp/interp.go index 8da27705f..cab9d9e35 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. @@ -110,17 +110,26 @@ 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()) } + // 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 } - call.EraseFromParentAsInstruction() for index, obj := range mem.objects { r.objects[index] = obj } @@ -270,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/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/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/interp/testdata/revert.ll b/interp/testdata/revert.ll new file mode 100644 index 000000000..41fb6a81e --- /dev/null +++ b/interp/testdata/revert.ll @@ -0,0 +1,32 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +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) + ret void +} diff --git a/interp/testdata/revert.out.ll b/interp/testdata/revert.out.ll new file mode 100644 index 000000000..4f38e4c41 --- /dev/null +++ b/interp/testdata/revert.out.ll @@ -0,0 +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 +} diff --git a/main.go b/main.go index 24d943624..c9fd0c042 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") @@ -1018,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)") @@ -1081,6 +1082,7 @@ func main() { GC: *gc, PanicStrategy: *panicStrategy, Scheduler: *scheduler, + Serial: *serial, PrintIR: *printIR, DumpSSA: *dumpSSA, VerifyIR: *verifyIR, 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/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-sense.go b/src/machine/board_feather-nrf52840-sense.go new file mode 100644 index 000000000..8a4f71446 --- /dev/null +++ b/src/machine/board_feather-nrf52840-sense.go @@ -0,0 +1,105 @@ +// +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 = D1 + UART_TX_PIN = D0 +) + +// 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 +) + +var ( + DefaultUART = UART0 +) diff --git a/src/machine/board_feather-nrf52840.go b/src/machine/board_feather-nrf52840.go index 641a9de81..e433e1037 100644 --- a/src/machine/board_feather-nrf52840.go +++ b/src/machine/board_feather-nrf52840.go @@ -72,13 +72,8 @@ const ( // UART0 pins (logical UART1) const ( - UART_RX_PIN = D0 - UART_TX_PIN = D1 -) - -// Serial is the USB device -var ( - Serial = USB + UART_RX_PIN = D1 + UART_TX_PIN = D0 ) // I2C pins @@ -104,3 +99,7 @@ var ( usb_VID uint16 = 0x239A usb_PID uint16 = 0x802A ) + +var ( + DefaultUART = UART0 +) 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_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_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_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/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_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_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/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/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 +} 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/src/net/mac.go b/src/net/mac.go index 13f505192..815b2738f 100644 --- a/src/net/mac.go +++ b/src/net/mac.go @@ -7,3 +7,81 @@ 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} +} 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 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/runtime/arch_tinygowasm.go b/src/runtime/arch_tinygowasm.go index 0ee3afd3b..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 @@ -55,3 +57,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 +} 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/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. 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) 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/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..26088d531 100644 --- a/targets/clue-alpha.json +++ b/targets/clue-alpha.json @@ -1,6 +1,8 @@ { "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/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-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 190d4d8f9..1c5b67e86 100644 --- a/targets/feather-m4-can.json +++ b/targets/feather-m4-can.json @@ -1,6 +1,8 @@ { "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 ccf06ec54..4c33ddd8f 100644 --- a/targets/feather-m4.json +++ b/targets/feather-m4.json @@ -1,6 +1,8 @@ { "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 new file mode 100644 index 000000000..b39c82105 --- /dev/null +++ b/targets/feather-nrf52840-sense.json @@ -0,0 +1,12 @@ +{ + "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", + "msd-firmware-name": "firmware.uf2", + "uf2-family-id": "0xADA52840", + "linkerscript": "targets/circuitplay-bluefruit.ld" +} diff --git a/targets/feather-nrf52840.json b/targets/feather-nrf52840.json index f0b706186..a4c491956 100644 --- a/targets/feather-nrf52840.json +++ b/targets/feather-nrf52840.json @@ -1,6 +1,8 @@ { "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/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/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..392b55502 100644 --- a/targets/grandcentral-m4.json +++ b/targets/grandcentral-m4.json @@ -1,6 +1,8 @@ { "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/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-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-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..d657b8a96 100644 --- a/targets/itsybitsy-nrf52840.json +++ b/targets/itsybitsy-nrf52840.json @@ -1,6 +1,8 @@ { "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/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/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 a282ac55a..33ffd61cf 100644 --- a/targets/metro-m4-airlift.json +++ b/targets/metro-m4-airlift.json @@ -1,6 +1,8 @@ { "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/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/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"] +} 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 fb74a2e74..461e0746b 100644 --- a/targets/nano-rp2040.json +++ b/targets/nano-rp2040.json @@ -2,9 +2,10 @@ "inherits": [ "rp2040" ], + "serial": "uart", "build-tags": ["nano_rp2040"], "linkerscript": "targets/pico.ld", "extra-files": [ - "targets/pico_boot_stage2.S" + "targets/pico-boot-stage2.S" ] } 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..4f4ab6e33 100644 --- a/targets/pygamer.json +++ b/targets/pygamer.json @@ -1,6 +1,8 @@ { "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/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/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/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/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", diff --git a/targets/wioterminal.json b/targets/wioterminal.json index 093947e16..5564d0761 100644 --- a/targets/wioterminal.json +++ b/targets/wioterminal.json @@ -1,6 +1,8 @@ { "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/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", 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", 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 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()) 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) }