Merge remote-tracking branch 'origin/dev' into dev

This commit is contained in:
ardnew
2021-08-02 13:37:21 -05:00
170 changed files with 1515 additions and 229 deletions
+66
View File
@@ -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
---
+9 -1
View File
@@ -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
+7 -2
View File
@@ -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)
+78 -31
View File
@@ -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.
+18 -6
View File
@@ -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
}
+11
View File
@@ -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 {
+1
View File
@@ -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"`
+12 -4
View File
@@ -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"):
+1
View File
@@ -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"},
}
+10
View File
@@ -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]
}
}
}
}
+30 -8
View File
@@ -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
}
+66
View File
@@ -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
+59
View File
@@ -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" }
+1 -1
View File
@@ -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.
+1
View File
@@ -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}},
+27 -2
View File
@@ -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
}
}
}
+1
View File
@@ -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) {
+11
View File
@@ -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
}
+32
View File
@@ -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
}
+21
View File
@@ -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
}
+3 -1
View File
@@ -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,
+14 -15
View File
@@ -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()
-2
View File
@@ -47,8 +47,6 @@ const (
LED = D6
)
var Serial = USB
// USBCDC pins
const (
USBCDC_DM_PIN Pin = PA24
-2
View File
@@ -35,8 +35,6 @@ const (
LED3 Pin = PB03 // RX LED
)
var Serial = USB
// ADC pins
const (
AREF Pin = PA03
-2
View File
@@ -74,5 +74,3 @@ const (
PB30 Pin = 62
PB31 Pin = 63
)
var Serial = USB
-2
View File
@@ -15,8 +15,6 @@ const (
BUTTON = PB31
)
var Serial = USB
const (
// https://ww1.microchip.com/downloads/en/DeviceDoc/70005321A.pdf
+1 -1
View File
@@ -17,7 +17,7 @@ const (
BUTTON = PA0
)
var Serial = UART1
var DefaultUART = UART1
// UART pins
const (
@@ -57,8 +57,6 @@ const (
UART_RX_PIN = P0_30 // PORTB
)
var Serial = USB
// I2C pins
const (
SDA_PIN = P0_05 // I2C0 external
-5
View File
@@ -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
-2
View File
@@ -68,8 +68,6 @@ const (
ADC3 Pin = IO39
)
var Serial = UART0
// UART0 pins
const (
UART_TX_PIN = IO1
-2
View File
@@ -47,8 +47,6 @@ const (
WS2812 = D8
)
var Serial = USB
// USBCDC pins
const (
USBCDC_DM_PIN = PA24
-2
View File
@@ -40,8 +40,6 @@ const (
WS2812 = D8
)
var Serial = USB
// USBCDC pins
const (
USBCDC_DM_PIN = PA24
+105
View File
@@ -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
)
+6 -7
View File
@@ -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
)
+1 -1
View File
@@ -141,7 +141,7 @@ var (
TxAltFuncSelector: AF7_USART1_2_3,
RxAltFuncSelector: AF7_USART1_2_3,
}
Serial = UART1
DefaultUART = UART1
)
func initUART() {
+17
View File
@@ -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
)
-2
View File
@@ -142,8 +142,6 @@ const (
WS2812 = NEOPIXEL_PIN
)
var Serial = USB
// UART pins
const (
UART1_RX_PIN = D0 // (PB25)
+1 -1
View File
@@ -35,7 +35,7 @@ const (
LED_BLUE = P21
)
var Serial = UART0
var DefaultUART = UART0
const (
// TODO: figure out the pin numbers for these.
-2
View File
@@ -37,8 +37,6 @@ const (
LED = D13
)
var Serial = USB
// USBCDC pins
const (
USBCDC_DM_PIN = PA24
-5
View File
@@ -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
+1 -1
View File
@@ -54,7 +54,7 @@ const (
I2C0_SDA_PIN = PA10
)
var Serial = UART0
var DefaultUART = UART0
var (
+1 -1
View File
@@ -52,7 +52,7 @@ const (
LED_BLUE = D14
)
var Serial = UART0
var DefaultUART = UART0
// Default pins for UARTHS.
const (
-2
View File
@@ -41,8 +41,6 @@ const (
WS2812 = D40
)
var Serial = USB
// USBCDC pins
const (
USBCDC_DM_PIN = PA24
+1 -1
View File
@@ -12,7 +12,7 @@ const (
BUTTONB Pin = P11
)
var Serial = UART0
var DefaultUART = UART0
// UART pins
const (
+1 -1
View File
@@ -12,7 +12,7 @@ const (
BUTTONB Pin = 26
)
var Serial = UART0
var DefaultUART = UART0
// UART pins
const (
-5
View File
@@ -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
+6 -1
View File
@@ -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
-5
View File
@@ -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
-2
View File
@@ -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
@@ -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
-3
View File
@@ -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
+1 -1
View File
@@ -34,7 +34,7 @@ var (
Buffer: NewRingBuffer(),
Bus: stm32.USART2,
}
Serial = UART2
DefaultUART = UART2
)
func init() {
+1 -1
View File
@@ -38,7 +38,7 @@ var (
TxAltFuncSelector: UART_ALT_FN,
RxAltFuncSelector: UART_ALT_FN,
}
Serial = UART1
DefaultUART = UART1
)
func init() {
+1 -1
View File
@@ -76,7 +76,7 @@ var (
TxAltFuncSelector: 4,
RxAltFuncSelector: 4,
}
Serial = UART1
DefaultUART = UART1
// I2C1 is documented, alias to I2C0 as well
I2C1 = &I2C{
+1 -1
View File
@@ -78,7 +78,7 @@ var (
TxAltFuncSelector: 7,
RxAltFuncSelector: 3,
}
Serial = UART1
DefaultUART = UART1
// I2C1 is documented, alias to I2C0 as well
I2C1 = &I2C{
+1 -1
View File
@@ -38,7 +38,7 @@ var (
TxAltFuncSelector: UART_ALT_FN,
RxAltFuncSelector: UART_ALT_FN,
}
Serial = UART1
DefaultUART = UART1
)
const (
+1 -1
View File
@@ -41,7 +41,7 @@ const (
// UART
var (
Serial = UART0
DefaultUART = UART0
)
const (
+1 -1
View File
@@ -41,7 +41,7 @@ const (
// UART
var (
Serial = UART0
DefaultUART = UART0
)
const (
+1 -1
View File
@@ -41,7 +41,7 @@ const (
// UART
var (
Serial = UART0
DefaultUART = UART0
)
const (
+1 -1
View File
@@ -19,7 +19,7 @@ const (
LED_BLUE Pin = 23
)
var Serial = UART0
var DefaultUART = UART0
// UART pins
const (
+1 -1
View File
@@ -23,7 +23,7 @@ const (
BUTTON4 Pin = 16
)
var Serial = UART0
var DefaultUART = UART0
// UART pins for NRF52840-DK
const (
+1 -1
View File
@@ -22,7 +22,7 @@ const (
BUTTON4 Pin = 25
)
var Serial = UART0
var DefaultUART = UART0
// UART pins
const (
-5
View File
@@ -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
+17
View File
@@ -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
)
+1 -1
View File
@@ -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:
-2
View File
@@ -67,8 +67,6 @@ const (
BUTTON_B_MASK = 128
)
var Serial = USB
// USBCDC pins
const (
USBCDC_DM_PIN = PA24
-2
View File
@@ -70,8 +70,6 @@ const (
BUTTON_B_MASK = 128
)
var Serial = USB
// USBCDC pins
const (
USBCDC_DM_PIN = PA24
-2
View File
@@ -95,8 +95,6 @@ const (
LED = D13
)
var Serial = USB
// USBCDC pins
const (
USBCDC_DM_PIN = PA24
+1 -1
View File
@@ -29,7 +29,7 @@ const (
BUTTON Pin = 7
)
var Serial = UART0
var DefaultUART = UART0
// UART pins
const (
+1 -1
View File
@@ -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
+2
View File
@@ -87,6 +87,8 @@ var (
TeensyUART5 = UART4
)
var DefaultUART = UART0
const (
defaultUART0RX = D00
defaultUART0TX = D01
+3 -3
View File
@@ -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(),
-2
View File
@@ -325,8 +325,6 @@ const (
OUTPUT_CTR_3V3 = PC15
)
var Serial = USB
// USBCDC pins
const (
USBCDC_DM_PIN = PIN_USB_DM
+1 -1
View File
@@ -27,4 +27,4 @@ const (
const HasLowFrequencyCrystal = true
var Serial = UART0
var DefaultUART = UART0
+1 -1
View File
@@ -122,7 +122,7 @@ func (i2c *I2C) readByte() byte {
}
// Always use UART0 as the serial output.
var Serial = UART0
var DefaultUART = UART0
// UART
var (
+2
View File
@@ -251,6 +251,8 @@ func (p Pin) mux() *volatile.Register32 {
}
}
var DefaultUART = UART0
var (
UART0 = &_UART0
_UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()}
+2
View File
@@ -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()}
+6 -6
View File
@@ -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)
+1 -1
View File
@@ -108,7 +108,7 @@ var (
}
)
var Serial = UART0
var DefaultUART = UART0
func init() {
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
+3
View File
@@ -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)
}
}
+361
View File
@@ -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, rp.SPI0_SSPCR0_SCR_Msk, 0)
return nil
}
func (spi SPI) GetBaudRate() uint32 {
const freqin uint32 = 125 * MHz
prescale := spi.Bus.SSPCPSR.Get()
postdiv := ((spi.Bus.SSPCR0.Get() & rp.SPI0_SSPCR0_SCR_Msk) >> 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<<rp.SPI0_SSPCR0_SPH_Pos)|
(cpol<<rp.SPI0_SSPCR0_SPO_Pos)|
(uint32(databits-1)<<rp.SPI0_SSPCR0_DSS_Pos)| // Set databits (SPI word length). Valid inputs are 4-16.
(frameFormat&0b11)<<rp.SPI0_SSPCR0_FRF_Pos, // Frame format bits 4:5
rp.SPI0_SSPCR0_SPH_Msk|rp.SPI0_SSPCR0_SPO_Msk|rp.SPI0_SSPCR0_DSS_Msk|rp.SPI0_SSPCR0_FRF_Msk, 0)
}
// reset resets SPI and waits until reset is done.
//go:inline
func (spi SPI) reset() {
resetVal := spi.deinit()
rp.RESETS.RESET.ClearBits(resetVal)
// Wait until reset is done.
for !rp.RESETS.RESET_DONE.HasBits(resetVal) {
}
}
//go:inline
func (spi SPI) deinit() (resetVal uint32) {
switch spi.Bus {
case rp.SPI0:
resetVal = rp.RESETS_RESET_SPI0
case rp.SPI1:
resetVal = rp.RESETS_RESET_SPI1
}
// Perform SPI reset.
rp.RESETS.RESET.SetBits(resetVal)
return resetVal
}
// isWritable returns false if no space is available to write. True if a write is possible
//go:inline
func (spi SPI) isWritable() bool {
return spi.Bus.SSPSR.HasBits(rp.SPI0_SSPSR_TNF)
}
// isReadable returns true if a read is possible i.e. data is present
//go:inline
func (spi SPI) isReadable() bool {
return spi.Bus.SSPSR.HasBits(rp.SPI0_SSPSR_RNE)
}
// PrintRegs prints SPI's peripheral common registries current values
func (spi SPI) PrintRegs() {
cr0 := spi.Bus.SSPCR0.Get()
cr1 := spi.Bus.SSPCR1.Get()
dmacr := spi.Bus.SSPDMACR.Get()
cpsr := spi.Bus.SSPCPSR.Get()
dr := spi.Bus.SSPDR.Get()
ris := spi.Bus.SSPRIS.Get()
println("CR0:", cr0)
println("CR1:", cr1)
println("DMACR:", dmacr)
println("CPSR:", cpsr)
println("DR:", dr)
println("RIS:", ris)
}
//go:inline
func (spi SPI) isBusy() bool {
return spi.Bus.SSPSR.HasBits(rp.SPI0_SSPSR_BSY)
}
// tx writes buffer to SPI ignoring Rx.
func (spi SPI) tx(tx []byte) error {
var deadline = ticks() + _SPITimeout
// Write to TX FIFO whilst ignoring RX, then clean up afterward. When RX
// is full, PL022 inhibits RX pushes, and sets a sticky flag on
// push-on-full, but continues shifting. Safe if SSPIMSC_RORIM is not set.
for i := range tx {
for !spi.isWritable() {
if ticks() > 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
}
+6
View File
@@ -0,0 +1,6 @@
// +build baremetal,serial.none
package machine
// Serial is a null device: writes to it are ignored.
var Serial = NullSerial{}
+6
View File
@@ -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
+6
View File
@@ -0,0 +1,6 @@
// +build baremetal,serial.usb
package machine
// Serial is implemented via USB (USB-CDC).
var Serial = USB
+46
View File
@@ -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
}
-6
View File
@@ -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 {
+78
View File
@@ -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}
}
+12
View File
@@ -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
+12
View File
@@ -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()
}
-5
View File
@@ -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
}
+28
View File
@@ -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()
}
+52 -2
View File
@@ -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
}
+21
View File
@@ -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
}
+8
View File
@@ -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.
+6
View File
@@ -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
)
+6
View File
@@ -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
)
-21
View File
@@ -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() {
+8
View File
@@ -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()
+17 -7
View File
@@ -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)
+13
View File
@@ -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 }

Some files were not shown because too many files have changed in this diff Show More