Merge branch 'dev' into feature/usb-common

This commit is contained in:
ardnew
2021-08-02 13:39:59 -05:00
254 changed files with 4461 additions and 531 deletions
@@ -0,0 +1,45 @@
name: CI for tinygo-dev docker container
on:
push:
branches: [ dev ]
jobs:
push_to_registry:
name: Push Docker image to GHCR/Docker Hub
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
steps:
- name: Check out the repo
uses: actions/checkout@v2
with:
submodules: recursive
- name: Docker meta
id: meta
uses: docker/metadata-action@v3
with:
images: |
tinygo/tinygo-dev
ghcr.io/${{ github.repository }}/tinygo-dev
tags: |
type=sha,format=long
type=raw,value=latest
- name: Log in to Docker Hub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKER_HUB_USERNAME }}
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
- name: Log in to Github Container Registry
uses: docker/login-action@v1
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
+2
View File
@@ -16,6 +16,8 @@ src/device/stm32/*.go
src/device/stm32/*.s src/device/stm32/*.s
src/device/kendryte/*.go src/device/kendryte/*.go
src/device/kendryte/*.s src/device/kendryte/*.s
src/device/rp/*.go
src/device/rp/*.s
vendor vendor
llvm-build llvm-build
llvm-project llvm-project
+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 0.18.0
--- ---
+14 -2
View File
@@ -230,6 +230,8 @@ smoketest:
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/mcp3008 $(TINYGO) build -size short -o test.hex -target=pca10040 examples/mcp3008
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/memstats
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit examples/microbit-blink $(TINYGO) build -size short -o test.hex -target=microbit examples/microbit-blink
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/pininterrupt $(TINYGO) build -size short -o test.hex -target=pca10040 examples/pininterrupt
@@ -334,9 +336,11 @@ smoketest:
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/blinky1
@$(MD5SUM) test.hex @$(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 $(TINYGO) build -size short -o test.hex -target=itsybitsy-nrf52840 examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=qtpy examples/blinky1 $(TINYGO) build -size short -o test.hex -target=qtpy examples/serial
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy40 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=teensy40 examples/blinky1
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
@@ -354,7 +358,13 @@ smoketest:
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-nano33 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=arduino-nano33 examples/blinky1
@$(MD5SUM) test.hex @$(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 @$(MD5SUM) test.hex
# test pwm # test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm $(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@@ -428,6 +438,8 @@ endif
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=1 examples/blinky1 $(TINYGO) build -size short -o test.hex -target=pca10040 -opt=1 examples/blinky1
@$(MD5SUM) test.hex @$(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 $(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
@$(MD5SUM) test.nro @$(MD5SUM) test.nro
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go $(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
+8 -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. You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
The following 62 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 Bluefruit](https://www.adafruit.com/product/4333)
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333) * [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
@@ -52,6 +52,8 @@ The following 62 microcontroller boards are currently supported:
* [Adafruit Feather M4](https://www.adafruit.com/product/3857) * [Adafruit Feather M4](https://www.adafruit.com/product/3857)
* [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759) * [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759)
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062) * [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 Feather STM32F405 Express](https://www.adafruit.com/product/4382)
* [Adafruit Grand Central M4](https://www.adafruit.com/product/4064) * [Adafruit Grand Central M4](https://www.adafruit.com/product/4064)
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727) * [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
@@ -68,7 +70,10 @@ The following 62 microcontroller boards are currently supported:
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3) * [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi) * [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
* [Arduino Nano](https://store.arduino.cc/arduino-nano) * [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 Uno](https://store.arduino.cc/arduino-uno-rev3)
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero) * [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
* [BBC micro:bit](https://microbit.org/) * [BBC micro:bit](https://microbit.org/)
@@ -95,6 +100,7 @@ The following 62 microcontroller boards are currently supported:
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html) * [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.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) * [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 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 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) * [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
+144 -65
View File
@@ -12,7 +12,9 @@ import (
"errors" "errors"
"fmt" "fmt"
"go/types" "go/types"
"hash/crc32"
"io/ioutil" "io/ioutil"
"math/bits"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
@@ -98,7 +100,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
AutomaticStackSize: config.AutomaticStackSize(), AutomaticStackSize: config.AutomaticStackSize(),
DefaultStackSize: config.Target.DefaultStackSize, DefaultStackSize: config.Target.DefaultStackSize,
NeedsStackObjects: config.NeedsStackObjects(), NeedsStackObjects: config.NeedsStackObjects(),
Debug: config.Debug(), Debug: true,
LLVMFeatures: config.LLVMFeatures(), LLVMFeatures: config.LLVMFeatures(),
} }
@@ -468,33 +470,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
linkerDependencies = append(linkerDependencies, job) 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 // 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 // contain things like the interrupt vector table and low level operations
// such as stack switching. // such as stack switching.
root := goenv.Get("TINYGOROOT")
for _, path := range config.ExtraFiles() { for _, path := range config.ExtraFiles() {
abspath := filepath.Join(root, path) abspath := filepath.Join(root, path)
job := &compileJob{ job := &compileJob{
@@ -535,6 +514,64 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
ldflags = append(ldflags, lprogram.LDFlags...) 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 // Create a linker job, which links all object files together and does some
// extra stuff that can only be done after linking. // extra stuff that can only be done after linking.
jobs = append(jobs, &compileJob{ jobs = append(jobs, &compileJob{
@@ -547,8 +584,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
} }
ldflags = append(ldflags, dependency.result) ldflags = append(ldflags, dependency.result)
} }
if config.Options.PrintCommands { if config.Options.PrintCommands != nil {
fmt.Printf("%s %s\n", config.Target.Linker, strings.Join(ldflags, " ")) config.Options.PrintCommands(config.Target.Linker, ldflags...)
} }
err = link(config.Target.Linker, ldflags...) err = link(config.Target.Linker, ldflags...)
if err != nil { if err != nil {
@@ -566,6 +603,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
return err return err
} }
} }
// Apply ELF patches
if config.AutomaticStackSize() { if config.AutomaticStackSize() {
// Modify the .tinygo_stacksizes section that contains a stack size // Modify the .tinygo_stacksizes section that contains a stack size
// for each goroutine. // for each goroutine.
@@ -574,6 +613,13 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
return fmt.Errorf("could not modify stack sizes: %w", err) return fmt.Errorf("could not modify stack sizes: %w", err)
} }
} }
if config.RP2040BootPatch() {
// Patch the second stage bootloader CRC into the .boot2 section
err = patchRP2040BootCRC(executable)
if err != nil {
return fmt.Errorf("could not patch RP2040 second stage boot loader: %w", err)
}
}
if config.Options.PrintSizes == "short" || config.Options.PrintSizes == "full" { if config.Options.PrintSizes == "short" || config.Options.PrintSizes == "full" {
sizes, err := loadProgramSize(executable) sizes, err := loadProgramSize(executable)
@@ -639,6 +685,18 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
if err != nil { if err != nil {
return err return err
} }
case "nrf-dfu":
// special format for nrfutil for Nordic chips
tmphexpath := filepath.Join(dir, "main.hex")
err := objcopy(executable, tmphexpath, "hex")
if err != nil {
return err
}
tmppath = filepath.Join(dir, "main"+outext)
err = makeDFUFirmwareImage(config.Options, tmphexpath, tmppath)
if err != nil {
return err
}
default: default:
return fmt.Errorf("unknown output binary format: %s", outputBinaryFormat) return fmt.Errorf("unknown output binary format: %s", outputBinaryFormat)
} }
@@ -908,30 +966,7 @@ func determineStackSizes(mod llvm.Module, executable string) ([]string, map[stri
// stack size information. Before this modification, all stack sizes in the // stack size information. Before this modification, all stack sizes in the
// section assume the default stack size (which is relatively big). // section assume the default stack size (which is relatively big).
func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map[string]functionStackSize) error { func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map[string]functionStackSize) error {
fp, err := os.OpenFile(executable, os.O_RDWR, 0) data, fileHeader, err := getElfSectionData(executable, ".tinygo_stacksizes")
if err != nil {
return err
}
defer fp.Close()
elfFile, err := elf.NewFile(fp)
if err != nil {
return err
}
section := elfFile.Section(".tinygo_stacksizes")
if section == nil {
return errors.New("could not find .tinygo_stacksizes section")
}
if section.Size != section.FileSize {
// Sanity check.
return fmt.Errorf("expected .tinygo_stacksizes to have identical size and file size, got %d and %d", section.Size, section.FileSize)
}
// Read all goroutine stack sizes.
data := make([]byte, section.Size)
_, err = fp.ReadAt(data, int64(section.Offset))
if err != nil { if err != nil {
return err return err
} }
@@ -953,15 +988,19 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map
if fn.stackSizeType == stacksize.Bounded { if fn.stackSizeType == stacksize.Bounded {
stackSize := uint32(fn.stackSize) 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. // Add stack size used by interrupts.
switch elfFile.Machine { switch fileHeader.Machine {
case elf.EM_ARM: 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 // On Cortex-M (assumed here), this stack size is 8 words or 32
// bytes. This is only to store the registers that the interrupt // bytes. This is only to store the registers that the interrupt
// may modify, the interrupt will switch to the interrupt stack // may modify, the interrupt will switch to the interrupt stack
@@ -969,6 +1008,14 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map
// Some background: // Some background:
// https://interrupt.memfault.com/blog/cortex-m-rtos-context-switching // https://interrupt.memfault.com/blog/cortex-m-rtos-context-switching
stackSize += 32 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. // Finally write the stack size to the binary.
@@ -976,13 +1023,7 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map
} }
} }
// Write back the modified stack sizes. return replaceElfSection(executable, ".tinygo_stacksizes", data)
_, err = fp.WriteAt(data, int64(section.Offset))
if err != nil {
return err
}
return nil
} }
// printStacks prints the maximum stack depth for functions that are started as // printStacks prints the maximum stack depth for functions that are started as
@@ -1014,3 +1055,41 @@ func printStacks(calculatedStacks []string, stackSizes map[string]functionStackS
} }
} }
} }
// RP2040 second stage bootloader CRC32 calculation
//
// Spec: https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
// Section: 2.8.1.3.1. Checksum
func patchRP2040BootCRC(executable string) error {
bytes, _, err := getElfSectionData(executable, ".boot2")
if err != nil {
return err
}
if len(bytes) != 256 {
return fmt.Errorf("rp2040 .boot2 section must be exactly 256 bytes")
}
// From the 'official' RP2040 checksum script:
//
// Our bootrom CRC32 is slightly bass-ackward but it's
// best to work around for now (FIXME)
// 100% worth it to save two Thumb instructions
revBytes := make([]byte, len(bytes))
for i := range bytes {
revBytes[i] = bits.Reverse8(bytes[i])
}
// crc32.Update does an initial negate and negates the
// result, so to meet RP2040 spec, pass 0x0 as initial
// hash and negate returned value.
//
// Note: checksum is over 252 bytes (256 - 4)
hash := bits.Reverse32(crc32.Update(0x0, crc32.IEEETable, revBytes[:252]) ^ 0xFFFFFFFF)
// Write the CRC to the end of the bootloader.
binary.LittleEndian.PutUint32(bytes[252:], hash)
// Update the .boot2 section to included the CRC
return replaceElfSection(executable, ".boot2", bytes)
}
+3 -3
View File
@@ -56,7 +56,7 @@ import (
// depfile but without invalidating its name. For this reason, the depfile is // depfile but without invalidating its name. For this reason, the depfile is
// written on each new compilation (even when it seems unnecessary). However, it // written on each new compilation (even when it seems unnecessary). However, it
// could in rare cases lead to a stale file fetched from the cache. // could in rare cases lead to a stale file fetched from the cache.
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands bool) (string, error) { func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands func(string, ...string)) (string, error) {
// Hash input file. // Hash input file.
fileHash, err := hashFile(abspath) fileHash, err := hashFile(abspath)
if err != nil { if err != nil {
@@ -128,8 +128,8 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
// flags (for the assembler) is a compiler error. // flags (for the assembler) is a compiler error.
flags = append(flags, "-Qunused-arguments") flags = append(flags, "-Qunused-arguments")
} }
if printCommands { if printCommands != nil {
fmt.Printf("clang %s\n", strings.Join(flags, " ")) printCommands("clang", flags...)
} }
err = runCCompiler(flags...) err = runCCompiler(flags...)
if err != nil { if err != nil {
+57
View File
@@ -0,0 +1,57 @@
package builder
import (
"debug/elf"
"fmt"
"os"
)
func getElfSectionData(executable string, sectionName string) ([]byte, elf.FileHeader, error) {
elfFile, err := elf.Open(executable)
if err != nil {
return nil, elf.FileHeader{}, err
}
defer elfFile.Close()
section := elfFile.Section(sectionName)
if section == nil {
return nil, elf.FileHeader{}, fmt.Errorf("could not find %s section", sectionName)
}
data, err := section.Data()
return data, elfFile.FileHeader, err
}
func replaceElfSection(executable string, sectionName string, data []byte) error {
fp, err := os.OpenFile(executable, os.O_RDWR, 0)
if err != nil {
return err
}
defer fp.Close()
elfFile, err := elf.Open(executable)
if err != nil {
return err
}
defer elfFile.Close()
section := elfFile.Section(sectionName)
if section == nil {
return fmt.Errorf("could not find %s section", sectionName)
}
// Implicitly check for compressed sections
if section.Size != section.FileSize {
return fmt.Errorf("expected section %s to have identical size and file size, got %d and %d", sectionName, section.Size, section.FileSize)
}
// Only permit complete replacement of section
if section.Size != uint64(len(data)) {
return fmt.Errorf("expected section %s to have size %d, was actually %d", sectionName, len(data), section.Size)
}
// Write the replacement section data
_, err = fp.WriteAt(data, int64(section.Offset))
return err
}
+27
View File
@@ -0,0 +1,27 @@
package builder
import (
"fmt"
"io/ioutil"
"os/exec"
"github.com/tinygo-org/tinygo/compileopts"
)
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fug_nrfutil%2FUG%2Fnrfutil%2Fnrfutil_intro.html
func makeDFUFirmwareImage(options *compileopts.Options, infile, outfile string) error {
cmdLine := []string{"nrfutil", "pkg", "generate", "--hw-version", "52", "--sd-req", "0x0", "--debug-mode", "--application", infile, outfile}
if options.PrintCommands != nil {
options.PrintCommands(cmdLine[0], cmdLine[1:]...)
}
cmd := exec.Command(cmdLine[0], cmdLine[1:]...)
cmd.Stdout = ioutil.Discard
err := cmd.Run()
if err != nil {
return fmt.Errorf("could not run nrfutil pkg generate: %w", err)
}
return nil
}
+33 -7
View File
@@ -55,7 +55,7 @@ func (c *Config) GOARCH() string {
// BuildTags returns the complete list of build tags used during this build. // BuildTags returns the complete list of build tags used during this build.
func (c *Config) BuildTags() []string { 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++ { for i := 1; i <= c.GoMinorVersion; i++ {
tags = append(tags, fmt.Sprintf("go1.%d", i)) tags = append(tags, fmt.Sprintf("go1.%d", i))
} }
@@ -89,7 +89,7 @@ func (c *Config) NeedsStackObjects() bool {
switch c.GC() { switch c.GC() {
case "conservative", "extalloc": case "conservative", "extalloc":
for _, tag := range c.BuildTags() { for _, tag := range c.BuildTags() {
if tag == "wasm" { if tag == "tinygo.wasm" {
return true return true
} }
} }
@@ -113,6 +113,18 @@ func (c *Config) Scheduler() string {
return "coroutines" 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 // OptLevels returns the optimization level (0-2), size level (0-2), and inliner
// threshold as used in the LLVM optimization pipeline. // threshold as used in the LLVM optimization pipeline.
func (c *Config) OptLevels() (optLevel, sizeLevel int, inlinerThreshold uint) { func (c *Config) OptLevels() (optLevel, sizeLevel int, inlinerThreshold uint) {
@@ -176,6 +188,15 @@ func (c *Config) AutomaticStackSize() bool {
return false return false
} }
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
// calculates and patches in the checksum for the 2nd stage bootloader.
func (c *Config) RP2040BootPatch() bool {
if c.Target.RP2040BootPatch != nil {
return *c.Target.RP2040BootPatch
}
return false
}
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo // CFlags returns the flags to pass to the C compiler. This is necessary for CGo
// preprocessing. // preprocessing.
func (c *Config) CFlags() []string { func (c *Config) CFlags() []string {
@@ -188,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, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include"))
cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include")) cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include"))
} }
if c.Debug() { // Always emit debug information. It is optionally stripped at link time.
cflags = append(cflags, "-g") cflags = append(cflags, "-g")
}
return cflags return cflags
} }
@@ -229,8 +249,9 @@ func (c *Config) VerifyIR() bool {
return c.Options.VerifyIR return c.Options.VerifyIR
} }
// Debug returns whether to add debug symbols to the IR, for debugging with GDB // Debug returns whether debug (DWARF) information should be retained by the
// and similar. // linker. By default, debug information is retained but it can be removed with
// the -no-debug flag.
func (c *Config) Debug() bool { func (c *Config) Debug() bool {
return c.Options.Debug return c.Options.Debug
} }
@@ -254,6 +275,11 @@ func (c *Config) BinaryFormat(ext string) string {
// More information: // More information:
// https://github.com/Microsoft/uf2 // https://github.com/Microsoft/uf2
return "uf2" return "uf2"
case ".zip":
if c.Target.BinaryFormat != "" {
return c.Target.BinaryFormat
}
return "zip"
default: default:
// Use the ELF format for unrecognized file formats. // Use the ELF format for unrecognized file formats.
return "elf" return "elf"
+12 -1
View File
@@ -9,6 +9,7 @@ import (
var ( var (
validGCOptions = []string{"none", "leaking", "extalloc", "conservative"} validGCOptions = []string{"none", "leaking", "extalloc", "conservative"}
validSchedulerOptions = []string{"none", "tasks", "coroutines"} validSchedulerOptions = []string{"none", "tasks", "coroutines"}
validSerialOptions = []string{"none", "uart", "usb"}
validPrintSizeOptions = []string{"none", "short", "full"} validPrintSizeOptions = []string{"none", "short", "full"}
validPanicStrategyOptions = []string{"print", "trap"} validPanicStrategyOptions = []string{"print", "trap"}
validOptOptions = []string{"none", "0", "1", "2", "s", "z"} validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
@@ -22,10 +23,11 @@ type Options struct {
GC string GC string
PanicStrategy string PanicStrategy string
Scheduler string Scheduler string
Serial string
PrintIR bool PrintIR bool
DumpSSA bool DumpSSA bool
VerifyIR bool VerifyIR bool
PrintCommands bool PrintCommands func(cmd string, args ...string)
Debug bool Debug bool
PrintSizes string PrintSizes string
PrintAllocs *regexp.Regexp // regexp string PrintAllocs *regexp.Regexp // regexp string
@@ -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 != "" { if o.PrintSizes != "" {
valid := isInArray(validPrintSizeOptions, o.PrintSizes) valid := isInArray(validPrintSizeOptions, o.PrintSizes)
if !valid { if !valid {
+3
View File
@@ -31,6 +31,7 @@ type TargetSpec struct {
BuildTags []string `json:"build-tags"` BuildTags []string `json:"build-tags"`
GC string `json:"gc"` GC string `json:"gc"`
Scheduler string `json:"scheduler"` Scheduler string `json:"scheduler"`
Serial string `json:"serial"` // which serial output to use (uart, usb, none)
Linker string `json:"linker"` Linker string `json:"linker"`
RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt) RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt)
Libc string `json:"libc"` Libc string `json:"libc"`
@@ -40,10 +41,12 @@ type TargetSpec struct {
LDFlags []string `json:"ldflags"` LDFlags []string `json:"ldflags"`
LinkerScript string `json:"linkerscript"` LinkerScript string `json:"linkerscript"`
ExtraFiles []string `json:"extra-files"` ExtraFiles []string `json:"extra-files"`
RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
Emulator []string `json:"emulator" override:"copy"` // inherited Emulator must not be append Emulator []string `json:"emulator" override:"copy"` // inherited Emulator must not be append
FlashCommand string `json:"flash-command"` FlashCommand string `json:"flash-command"`
GDB []string `json:"gdb"` GDB []string `json:"gdb"`
PortReset string `json:"flash-1200-bps-reset"` PortReset string `json:"flash-1200-bps-reset"`
SerialPort []string `json:"serial-port"` // serial port IDs in the form "acm:vid:pid" or "usb:vid:pid"
FlashMethod string `json:"flash-method"` FlashMethod string `json:"flash-method"`
FlashVolume string `json:"msd-volume-name"` FlashVolume string `json:"msd-volume-name"`
FlashFilename string `json:"msd-firmware-name"` FlashFilename string `json:"msd-firmware-name"`
+12 -4
View File
@@ -23,7 +23,7 @@ import (
// Version of the compiler pacakge. Must be incremented each time the compiler // Version of the compiler pacakge. Must be incremented each time the compiler
// package changes in a way that affects the generated LLVM module. // package changes in a way that affects the generated LLVM module.
// This version is independent of the TinyGo version number. // This version is independent of the TinyGo version number.
const Version = 10 // last change: context parameter in go wrapper const Version = 12 // last change: implement syscall.rawSyscallNoError
func init() { func init() {
llvm.InitializeAllTargets() llvm.InitializeAllTargets()
@@ -715,11 +715,11 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
member := pkg.Members[name] member := pkg.Members[name]
switch member := member.(type) { switch member := member.(type) {
case *ssa.Function: case *ssa.Function:
// Create the function definition.
b := newBuilder(c, irbuilder, member)
if member.Blocks == nil { if member.Blocks == nil {
continue // external function continue // external function
} }
// Create the function definition.
b := newBuilder(c, irbuilder, member)
b.createFunction() b.createFunction()
case *ssa.Type: case *ssa.Type:
if types.IsInterface(member.Type()) { if types.IsInterface(member.Type()) {
@@ -758,10 +758,13 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
case *ssa.Global: case *ssa.Global:
// Global variable. // Global variable.
info := c.getGlobalInfo(member) info := c.getGlobalInfo(member)
global := c.getGlobal(member)
if !info.extern { if !info.extern {
global := c.getGlobal(member)
global.SetInitializer(llvm.ConstNull(global.Type().ElementType())) global.SetInitializer(llvm.ConstNull(global.Type().ElementType()))
global.SetVisibility(llvm.HiddenVisibility) 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.SetVisibility(llvm.HiddenVisibility)
b.llvmFn.SetUnnamedAddr(true) b.llvmFn.SetUnnamedAddr(true)
} }
if b.info.section != "" {
b.llvmFn.SetSection(b.info.section)
}
if b.info.exported && strings.HasPrefix(b.Triple, "wasm") { if b.info.exported && strings.HasPrefix(b.Triple, "wasm") {
// Set the exported name. This is necessary for WebAssembly because // Set the exported name. This is necessary for WebAssembly because
// otherwise the function is not exported. // otherwise the function is not exported.
@@ -1304,6 +1310,8 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
return b.emitCSROperation(instr) return b.emitCSROperation(instr)
case strings.HasPrefix(name, "syscall.Syscall"): case strings.HasPrefix(name, "syscall.Syscall"):
return b.createSyscall(instr) return b.createSyscall(instr)
case strings.HasPrefix(name, "syscall.rawSyscallNoError"):
return b.createRawSyscallNoError(instr)
case strings.HasPrefix(name, "runtime/volatile.Load"): case strings.HasPrefix(name, "runtime/volatile.Load"):
return b.createVolatileLoad(instr) return b.createVolatileLoad(instr)
case strings.HasPrefix(name, "runtime/volatile.Store"): case strings.HasPrefix(name, "runtime/volatile.Store"):
+1
View File
@@ -45,6 +45,7 @@ func TestCompiler(t *testing.T) {
{"float.go", ""}, {"float.go", ""},
{"interface.go", ""}, {"interface.go", ""},
{"func.go", ""}, {"func.go", ""},
{"pragma.go", ""},
{"goroutine.go", "wasm"}, {"goroutine.go", "wasm"},
{"goroutine.go", "cortex-m-qemu"}, {"goroutine.go", "cortex-m-qemu"},
} }
+13 -2
View File
@@ -311,10 +311,21 @@ func (c *compilerContext) getInterfaceMethodSet(typ types.Type) llvm.Value {
// used during the interface lowering pass. // used during the interface lowering pass.
func (c *compilerContext) getMethodSignature(method *types.Func) llvm.Value { func (c *compilerContext) getMethodSignature(method *types.Func) llvm.Value {
signature := methodSignature(method) signature := methodSignature(method)
signatureGlobal := c.mod.NamedGlobal("func " + signature) var globalName string
if token.IsExported(method.Name()) {
globalName = "reflect/methods." + signature
} else {
globalName = method.Type().(*types.Signature).Recv().Pkg().Path() + ".$methods." + signature
}
signatureGlobal := c.mod.NamedGlobal(globalName)
if signatureGlobal.IsNil() { if signatureGlobal.IsNil() {
signatureGlobal = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), "func "+signature) // TODO: put something useful in these globals, such as the method
// signature. Useful to one day implement reflect.Value.Method(n).
signatureGlobal = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), globalName)
signatureGlobal.SetInitializer(llvm.ConstInt(c.ctx.Int8Type(), 0, false))
signatureGlobal.SetLinkage(llvm.LinkOnceODRLinkage)
signatureGlobal.SetGlobalConstant(true) signatureGlobal.SetGlobalConstant(true)
signatureGlobal.SetAlignment(1)
} }
return signatureGlobal return signatureGlobal
} }
+10
View File
@@ -24,6 +24,7 @@ type functionInfo struct {
module string // go:wasm-module module string // go:wasm-module
importName string // go:linkname, go:export - The name the developer assigns 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 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 exported bool // go:export, CGo
nobounds bool // go:nobounds nobounds bool // go:nobounds
variadic bool // go:variadic (CGo only) variadic bool // go:variadic (CGo only)
@@ -270,6 +271,10 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
if hasUnsafeImport(f.Pkg.Pkg) { if hasUnsafeImport(f.Pkg.Pkg) {
info.linkName = parts[2] info.linkName = parts[2]
} }
case "//go:section":
if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) {
info.section = parts[1]
}
case "//go:nobounds": case "//go:nobounds":
// Skip bounds checking in this function. Useful for some // Skip bounds checking in this function. Useful for some
// runtime functions. // runtime functions.
@@ -325,6 +330,7 @@ type globalInfo struct {
linkName string // go:extern linkName string // go:extern
extern bool // go:extern extern bool // go:extern
align int // go:align align int // go:align
section string // go:section
} }
// loadASTComments loads comments on globals from the AST, for use later in the // 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 { if err == nil {
info.align = align 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" "tinygo.org/x/go-llvm"
) )
// createSyscall emits an inline system call instruction, depending on the // createRawSyscall creates a system call with the provided system call number
// target OS/arch. // and returns the result as a single integer (the system call result). The
func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) { // result is not further interpreted.
func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
num := b.getValue(call.Args[0]) num := b.getValue(call.Args[0])
var syscallResult llvm.Value
switch { switch {
case b.GOARCH == "amd64": case b.GOARCH == "amd64":
if b.GOOS == "darwin" { if b.GOOS == "darwin" {
@@ -57,7 +57,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
constraints += ",~{rcx},~{r11}" constraints += ",~{rcx},~{r11}"
fnType := llvm.FunctionType(b.uintptrType, argTypes, false) fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel) 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": case b.GOARCH == "386" && b.GOOS == "linux":
// Sources: // Sources:
// syscall(2) man page // 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) fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel) 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": case b.GOARCH == "arm" && b.GOOS == "linux":
// Implement the EABI system call convention for Linux. // Implement the EABI system call convention for Linux.
// Source: syscall(2) man page. // 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) fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0) 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": case b.GOARCH == "arm64" && b.GOOS == "linux":
// Source: syscall(2) man page. // Source: syscall(2) man page.
args := []llvm.Value{} args := []llvm.Value{}
@@ -147,10 +147,19 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
constraints += ",~{x16},~{x17}" // scratch registers constraints += ",~{x16},~{x17}" // scratch registers
fnType := llvm.FunctionType(b.uintptrType, argTypes, false) fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0) target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
syscallResult = b.CreateCall(target, args, "") return b.CreateCall(target, args, ""), nil
default: default:
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH) 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 { switch b.GOOS {
case "linux", "freebsd": case "linux", "freebsd":
// Return values: r0, r1 uintptr, err Errno // 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) 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
}
+1 -1
View File
@@ -5,7 +5,7 @@ target triple = "armv7m-none-eabi"
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* } %runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } } %runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i32, %"internal/task.state" } %"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
%"internal/task.state" = type { i32, i32* } %"internal/task.state" = type { i32, i32* }
%runtime.chanSelectState = type { %runtime.channel*, i8* } %runtime.chanSelectState = type { %runtime.channel*, i8* }
+1 -1
View File
@@ -6,7 +6,7 @@ target triple = "wasm32--wasi"
%runtime.funcValueWithSignature = type { i32, i8* } %runtime.funcValueWithSignature = type { i32, i8* }
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* } %runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } } %runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
%"internal/task.Task" = type { %"internal/task.Task"*, i8*, i32, %"internal/task.state" } %"internal/task.Task" = type { %"internal/task.Task"*, i8*, i64, %"internal/task.state" }
%"internal/task.state" = type { i8* } %"internal/task.state" = type { i8* }
%runtime.chanSelectState = type { %runtime.channel*, i8* } %runtime.chanSelectState = type { %runtime.channel*, i8* }
+6 -6
View File
@@ -13,15 +13,15 @@ target triple = "wasm32--wasi"
@"reflect/types.type:pointer:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:named:error", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null } @"reflect/types.type:pointer:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:named:error", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null }
@"reflect/types.type:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:named:error" } @"reflect/types.type:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:named:error" }
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{Error() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" } @"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{Error() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }
@"func Error() string" = external constant i8 @"reflect/methods.Error() string" = linkonce_odr constant i8 0, align 1
@"reflect/types.interface:interface{Error() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func Error() string"] @"reflect/types.interface:interface{Error() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"reflect/methods.Error() string"]
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null } @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null }
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{String:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null } @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{String:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null }
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{String() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" } @"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{String() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }
@"func String() string" = external constant i8 @"reflect/methods.String() string" = linkonce_odr constant i8 0, align 1
@"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func String() string"] @"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"reflect/methods.String() string"]
@"reflect/types.typeid:basic:int" = external constant i8 @"reflect/types.typeid:basic:int" = external constant i8
@"error$interface" = linkonce_odr constant [1 x i8*] [i8* @"func Error() string"] @"error$interface" = linkonce_odr constant [1 x i8*] [i8* @"reflect/methods.Error() string"]
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
@@ -92,7 +92,7 @@ typeassert.next: ; preds = %typeassert.ok, %ent
define hidden %runtime._string @main.callErrorMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr { define hidden %runtime._string @main.callErrorMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr {
entry: entry:
%invoke.func = call i32 @runtime.interfaceMethod(i32 %itf.typecode, i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"error$interface", i32 0, i32 0), i8* nonnull @"func Error() string", i8* undef, i8* null) %invoke.func = call i32 @runtime.interfaceMethod(i32 %itf.typecode, i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"error$interface", i32 0, i32 0), i8* nonnull @"reflect/methods.Error() string", i8* undef, i8* null)
%invoke.func.cast = inttoptr i32 %invoke.func to %runtime._string (i8*, i8*, i8*)* %invoke.func.cast = inttoptr i32 %invoke.func to %runtime._string (i8*, i8*, i8*)*
%0 = call %runtime._string %invoke.func.cast(i8* %itf.value, i8* undef, i8* undef) %0 = call %runtime._string %invoke.func.cast(i8* %itf.value, i8* undef, i8* undef)
ret %runtime._string %0 ret %runtime._string %0
+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. // Version of TinyGo.
// Update this value before release of new version of software. // Update this value before release of new version of software.
const Version = "0.19.0-dev" const Version = "0.20.0-dev"
// GetGorootVersion returns the major and minor version for a given GOROOT path. // GetGorootVersion returns the major and minor version for a given GOROOT path.
// If the goroot cannot be determined, (0, 0) is returned. // 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) pos := getPosition(inst.llvmInst)
return &Error{ return &Error{
ImportPath: r.pkgName, ImportPath: r.pkgName,
Inst: inst.llvmInst,
Pos: pos, Pos: pos,
Err: err, Err: err,
Traceback: []ErrorLine{{pos, inst.llvmInst}}, Traceback: []ErrorLine{{pos, inst.llvmInst}},
+34 -3
View File
@@ -15,7 +15,7 @@ import (
// package is changed in a way that affects the output so that cached package // package is changed in a way that affects the output so that cached package
// builds will be invalidated. // builds will be invalidated.
// This version is independent of the TinyGo version number. // 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. // Enable extra checks, which should be disabled by default.
// This may help track down bugs by adding a few more sanity checks. // 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()) fmt.Fprintln(os.Stderr, "call:", fn.Name())
} }
_, mem, callErr := r.run(r.getFunction(fn), nil, nil, " ") _, mem, callErr := r.run(r.getFunction(fn), nil, nil, " ")
call.EraseFromParentAsInstruction()
if callErr != nil { if callErr != nil {
if isRecoverableError(callErr.Err) { if isRecoverableError(callErr.Err) {
if r.debug { if r.debug {
fmt.Fprintln(os.Stderr, "not interpreting", r.pkgName, "because of error:", callErr.Error()) 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() 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 continue
} }
return callErr return callErr
} }
call.EraseFromParentAsInstruction()
for index, obj := range mem.objects { for index, obj := range mem.objects {
r.objects[index] = obj r.objects[index] = obj
} }
@@ -129,7 +138,7 @@ func Run(mod llvm.Module, debug bool) error {
// Update all global variables in the LLVM module. // Update all global variables in the LLVM module.
mem := memoryView{r: r} mem := memoryView{r: r}
for _, obj := range r.objects { for i, obj := range r.objects {
if obj.llvmGlobal.IsNil() { if obj.llvmGlobal.IsNil() {
continue continue
} }
@@ -159,6 +168,12 @@ func Run(mod llvm.Module, debug bool) error {
name := obj.llvmGlobal.Name() name := obj.llvmGlobal.Name()
obj.llvmGlobal.EraseFromParentAsGlobal() obj.llvmGlobal.EraseFromParentAsGlobal()
newGlobal.SetName(name) newGlobal.SetName(name)
// Update interp-internal references.
delete(r.globals, obj.llvmGlobal)
obj.llvmGlobal = newGlobal
r.globals[newGlobal] = i
r.objects[i] = obj
continue continue
} }
if err != nil { if err != nil {
@@ -264,3 +279,19 @@ func (r *runner) getFunction(llvmFn llvm.Value) *function {
r.functionCache[llvmFn] = fn r.functionCache[llvmFn] = fn
return 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", "slice-copy",
"consteval", "consteval",
"interface", "interface",
"revert",
} { } {
name := name // make tc local to this closure name := name // make tc local to this closure
t.Run(name, func(t *testing.T) { 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 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 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
}
+36 -15
View File
@@ -2,6 +2,14 @@ package loader
// This file constructs a new temporary GOROOT directory by merging both the // This file constructs a new temporary GOROOT directory by merging both the
// standard Go GOROOT and the GOROOT from TinyGo using symlinks. // standard Go GOROOT and the GOROOT from TinyGo using symlinks.
//
// The goal is to replace specific packages from Go with a TinyGo version. It's
// never a partial replacement, either a package is fully replaced or it is not.
// This is important because if we did allow to merge packages (e.g. by adding
// files to a package), it would lead to a dependency on implementation details
// with all the maintenance burden that results in. Only allowing to replace
// packages as a whole avoids this as packages are already designed to have a
// public (backwards-compatible) API.
import ( import (
"crypto/sha512" "crypto/sha512"
@@ -139,6 +147,7 @@ func mergeDirectory(goroot, tinygoroot, tmpgoroot, importPath string, overrides
if err != nil { if err != nil {
return err return err
} }
hasTinyGoFiles := false
for _, e := range tinygoEntries { for _, e := range tinygoEntries {
if e.IsDir() { if e.IsDir() {
// A directory, so merge this thing. // A directory, so merge this thing.
@@ -154,6 +163,7 @@ func mergeDirectory(goroot, tinygoroot, tmpgoroot, importPath string, overrides
if err != nil { if err != nil {
return err return err
} }
hasTinyGoFiles = true
} }
} }
@@ -164,21 +174,30 @@ func mergeDirectory(goroot, tinygoroot, tmpgoroot, importPath string, overrides
return err return err
} }
for _, e := range gorootEntries { for _, e := range gorootEntries {
if !e.IsDir() { if e.IsDir() {
// Don't merge in files from Go. Otherwise we'd end up with a if _, ok := overrides[path.Join(importPath, e.Name())+"/"]; ok {
// weird syscall package with files from both roots. // Already included above, so don't bother trying to create this
continue // symlink.
} continue
if _, ok := overrides[path.Join(importPath, e.Name())+"/"]; ok { }
// Already included above, so don't bother trying to create this newname := filepath.Join(tmpgoroot, "src", importPath, e.Name())
// symlink. oldname := filepath.Join(goroot, "src", importPath, e.Name())
continue err := symlink(oldname, newname)
} if err != nil {
newname := filepath.Join(tmpgoroot, "src", importPath, e.Name()) return err
oldname := filepath.Join(goroot, "src", importPath, e.Name()) }
err := symlink(oldname, newname) } else {
if err != nil { // Only merge files from Go if TinyGo does not have any files.
return err // Otherwise we'd end up with a weird mix from both Go
// implementations.
if !hasTinyGoFiles {
newname := filepath.Join(tmpgoroot, "src", importPath, e.Name())
oldname := filepath.Join(goroot, "src", importPath, e.Name())
err := symlink(oldname, newname)
if err != nil {
return err
}
}
} }
} }
} }
@@ -201,6 +220,8 @@ func needsSyscallPackage(buildTags []string) bool {
func pathsToOverride(needsSyscallPackage bool) map[string]bool { func pathsToOverride(needsSyscallPackage bool) map[string]bool {
paths := map[string]bool{ paths := map[string]bool{
"/": true, "/": true,
"crypto/": true,
"crypto/rand/": false,
"device/": false, "device/": false,
"examples/": false, "examples/": false,
"internal/": true, "internal/": true,
+5 -6
View File
@@ -343,12 +343,11 @@ func (p *Package) Check() error {
checker.Importer = p checker.Importer = p
packageName := p.ImportPath packageName := p.ImportPath
if p.Name == "main" { if p == p.program.MainPkg() {
// The main package normally has a different import path, such as if p.Name != "main" {
// "command-line-arguments" or "./testdata/cgo". Therefore, use the name // Sanity check. Should not ever trigger.
// "main" in such a case: this package isn't imported from anywhere. panic("expected main package to have name 'main'")
// This is safe as it isn't possible to import a package with the name }
// "main".
packageName = "main" packageName = "main"
} }
typesPkg, err := checker.Check(packageName, p.program.fset, p.Files, &p.info) typesPkg, err := checker.Check(packageName, p.program.fset, p.Files, &p.info)
+124 -36
View File
@@ -15,6 +15,7 @@ import (
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime" "runtime"
"strconv"
"strings" "strings"
"sync/atomic" "sync/atomic"
"time" "time"
@@ -95,12 +96,31 @@ func copyFile(src, dst string) error {
// executeCommand is a simple wrapper to exec.Cmd // executeCommand is a simple wrapper to exec.Cmd
func executeCommand(options *compileopts.Options, name string, arg ...string) *exec.Cmd { func executeCommand(options *compileopts.Options, name string, arg ...string) *exec.Cmd {
if options.PrintCommands { if options.PrintCommands != nil {
fmt.Printf("%s %s\n", name, strings.Join(arg, " ")) options.PrintCommands(name, arg...)
} }
return exec.Command(name, arg...) return exec.Command(name, arg...)
} }
// printCommand prints a command to stdout while formatting it like a real
// command (escaping characters etc). The resulting command should be easy to
// run directly in a shell, although it is not guaranteed to be a safe shell
// escape. That's not a problem as the primary use case is printing the command,
// not running it.
func printCommand(cmd string, args ...string) {
command := append([]string{cmd}, args...)
for i, arg := range command {
// Source: https://www.oreilly.com/library/view/learning-the-bash/1565923472/ch01s09.html
const specialChars = "~`#$&*()\\|[]{};'\"<>?! "
if strings.ContainsAny(arg, specialChars) {
// See: https://stackoverflow.com/questions/15783701/which-characters-need-to-be-escaped-when-using-bash
arg = "'" + strings.ReplaceAll(arg, `'`, `'\''`) + "'"
command[i] = arg
}
}
fmt.Fprintln(os.Stderr, strings.Join(command, " "))
}
// Build compiles and links the given package and writes it to outpath. // Build compiles and links the given package and writes it to outpath.
func Build(pkgName, outpath string, options *compileopts.Options) error { func Build(pkgName, outpath string, options *compileopts.Options) error {
config, err := builder.NewConfig(options) config, err := builder.NewConfig(options)
@@ -145,7 +165,7 @@ func Test(pkgName string, options *compileopts.Options, testCompileOnly bool, ou
return false, err return false, err
} }
var passed bool passed := true
err = builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error { err = builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error {
if testCompileOnly || outpath != "" { if testCompileOnly || outpath != "" {
// Write test binary to the specified file name. // Write test binary to the specified file name.
@@ -256,6 +276,8 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
fileExt = ".bin" fileExt = ".bin"
case strings.Contains(config.Target.FlashCommand, "{uf2}"): case strings.Contains(config.Target.FlashCommand, "{uf2}"):
fileExt = ".uf2" fileExt = ".uf2"
case strings.Contains(config.Target.FlashCommand, "{zip}"):
fileExt = ".zip"
default: default:
return errors.New("invalid target file - did you forget the {hex} token in the 'flash-command' section?") return errors.New("invalid target file - did you forget the {hex} token in the 'flash-command' section?")
} }
@@ -275,7 +297,7 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
return builder.Build(pkgName, fileExt, config, func(result builder.BuildResult) error { return builder.Build(pkgName, fileExt, config, func(result builder.BuildResult) error {
// do we need port reset to put MCU into bootloader mode? // do we need port reset to put MCU into bootloader mode?
if config.Target.PortReset == "true" && flashMethod != "openocd" { if config.Target.PortReset == "true" && flashMethod != "openocd" {
port, err := getDefaultPort(strings.FieldsFunc(port, func(c rune) bool { return c == ',' })) port, err := getDefaultPort(port, config.Target.SerialPort)
if err != nil { if err != nil {
return err return err
} }
@@ -293,36 +315,36 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
case "", "command": case "", "command":
// Create the command. // Create the command.
flashCmd := config.Target.FlashCommand flashCmd := config.Target.FlashCommand
fileToken := "{" + fileExt[1:] + "}" flashCmdList, err := shlex.Split(flashCmd)
flashCmd = strings.ReplaceAll(flashCmd, fileToken, result.Binary) if err != nil {
return fmt.Errorf("could not parse flash command %#v: %w", flashCmd, err)
}
if strings.Contains(flashCmd, "{port}") { if strings.Contains(flashCmd, "{port}") {
var err error var err error
port, err = getDefaultPort(strings.FieldsFunc(port, func(c rune) bool { return c == ',' })) port, err = getDefaultPort(port, config.Target.SerialPort)
if err != nil { if err != nil {
return err return err
} }
} }
flashCmd = strings.ReplaceAll(flashCmd, "{port}", port) // Fill in fields in the command template.
fileToken := "{" + fileExt[1:] + "}"
// Execute the command. for i, arg := range flashCmdList {
var cmd *exec.Cmd arg = strings.ReplaceAll(arg, fileToken, result.Binary)
switch runtime.GOOS { arg = strings.ReplaceAll(arg, "{port}", port)
case "windows": flashCmdList[i] = arg
command := strings.Split(flashCmd, " ")
if len(command) < 2 {
return errors.New("invalid flash command")
}
cmd = executeCommand(config.Options, command[0], command[1:]...)
default:
cmd = executeCommand(config.Options, "/bin/sh", "-c", flashCmd)
} }
// Execute the command.
if len(flashCmdList) < 2 {
return fmt.Errorf("invalid flash command: %#v", flashCmd)
}
cmd := executeCommand(config.Options, flashCmdList[0], flashCmdList[1:]...)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
cmd.Dir = goenv.Get("TINYGOROOT") cmd.Dir = goenv.Get("TINYGOROOT")
err := cmd.Run() err = cmd.Run()
if err != nil { if err != nil {
return &commandError{"failed to flash", result.Binary, err} return &commandError{"failed to flash", result.Binary, err}
} }
@@ -413,7 +435,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
case "native": case "native":
// Run GDB directly. // Run GDB directly.
case "openocd": case "openocd":
gdbCommands = append(gdbCommands, "target remote :3333", "monitor halt", "load", "monitor reset halt") gdbCommands = append(gdbCommands, "target extended-remote :3333", "monitor halt", "load", "monitor reset halt")
// We need a separate debugging daemon for on-chip debugging. // We need a separate debugging daemon for on-chip debugging.
args, err := config.OpenOCDConfiguration() args, err := config.OpenOCDConfiguration()
@@ -432,7 +454,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
daemon.Stderr = w daemon.Stderr = w
} }
case "jlink": case "jlink":
gdbCommands = append(gdbCommands, "target remote :2331", "load", "monitor reset halt") gdbCommands = append(gdbCommands, "target extended-remote :2331", "load", "monitor reset halt")
// We need a separate debugging daemon for on-chip debugging. // We need a separate debugging daemon for on-chip debugging.
daemon = executeCommand(config.Options, "JLinkGDBServer", "-device", config.Target.JLinkDevice) daemon = executeCommand(config.Options, "JLinkGDBServer", "-device", config.Target.JLinkDevice)
@@ -447,7 +469,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
daemon.Stderr = w daemon.Stderr = w
} }
case "qemu": case "qemu":
gdbCommands = append(gdbCommands, "target remote :1234") gdbCommands = append(gdbCommands, "target extended-remote :1234")
// Run in an emulator. // Run in an emulator.
args := append(config.Target.Emulator[1:], result.Binary, "-s", "-S") args := append(config.Target.Emulator[1:], result.Binary, "-s", "-S")
@@ -455,7 +477,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
daemon.Stdout = os.Stdout daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr daemon.Stderr = os.Stderr
case "qemu-user": case "qemu-user":
gdbCommands = append(gdbCommands, "target remote :1234") gdbCommands = append(gdbCommands, "target extended-remote :1234")
// Run in an emulator. // Run in an emulator.
args := append(config.Target.Emulator[1:], "-g", "1234", result.Binary) args := append(config.Target.Emulator[1:], "-g", "1234", result.Binary)
@@ -463,7 +485,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
daemon.Stdout = os.Stdout daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr daemon.Stderr = os.Stderr
case "mgba": case "mgba":
gdbCommands = append(gdbCommands, "target remote :2345") gdbCommands = append(gdbCommands, "target extended-remote :2345")
// Run in an emulator. // Run in an emulator.
args := append(config.Target.Emulator[1:], result.Binary, "-g") args := append(config.Target.Emulator[1:], result.Binary, "-g")
@@ -471,7 +493,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
daemon.Stdout = os.Stdout daemon.Stdout = os.Stdout
daemon.Stderr = os.Stderr daemon.Stderr = os.Stderr
case "simavr": case "simavr":
gdbCommands = append(gdbCommands, "target remote :1234") gdbCommands = append(gdbCommands, "target extended-remote :1234")
// Run in an emulator. // Run in an emulator.
args := append(config.Target.Emulator[1:], "-g", result.Binary) args := append(config.Target.Emulator[1:], "-g", result.Binary)
@@ -697,7 +719,8 @@ func windowsFindUSBDrive(volume string, options *compileopts.Options) (string, e
} }
// getDefaultPort returns the default serial port depending on the operating system. // getDefaultPort returns the default serial port depending on the operating system.
func getDefaultPort(portCandidates []string) (port string, err error) { func getDefaultPort(portFlag string, usbInterfaces []string) (port string, err error) {
portCandidates := strings.FieldsFunc(portFlag, func(c rune) bool { return c == ',' })
if len(portCandidates) == 1 { if len(portCandidates) == 1 {
return portCandidates[0], nil return portCandidates[0], nil
} }
@@ -713,13 +736,70 @@ func getDefaultPort(portCandidates []string) (port string, err error) {
return "", err return "", err
} }
for _, p := range portsList { var preferredPortIDs [][2]uint16
if p.IsUSB { for _, s := range usbInterfaces {
ports = append(ports, p.Name) parts := strings.Split(s, ":")
if len(parts) != 3 || (parts[0] != "acm" && parts[0] == "usb") {
// acm and usb are the two types of serial ports recognized
// under Linux (ttyACM*, ttyUSB*). Other operating systems don't
// generally make this distinction. If this is not one of the
// given USB devices, don't try to parse the USB IDs.
continue
} }
vid, err := strconv.ParseUint(parts[1], 16, 16)
if err != nil {
return "", fmt.Errorf("could not parse USB vendor ID %q: %w", parts[1], err)
}
pid, err := strconv.ParseUint(parts[2], 16, 16)
if err != nil {
return "", fmt.Errorf("could not parse USB product ID %q: %w", parts[1], err)
}
preferredPortIDs = append(preferredPortIDs, [2]uint16{uint16(vid), uint16(pid)})
} }
if ports == nil || len(ports) == 0 { var primaryPorts []string // ports picked from preferred USB VID/PID
var secondaryPorts []string // other ports (as a fallback)
for _, p := range portsList {
if !p.IsUSB {
continue
}
if p.VID != "" && p.PID != "" {
foundPort := false
vid, vidErr := strconv.ParseUint(p.VID, 16, 16)
pid, pidErr := strconv.ParseUint(p.PID, 16, 16)
if vidErr == nil && pidErr == nil {
for _, id := range preferredPortIDs {
if uint16(vid) == id[0] && uint16(pid) == id[1] {
primaryPorts = append(primaryPorts, p.Name)
foundPort = true
continue
}
}
}
if foundPort {
continue
}
}
secondaryPorts = append(secondaryPorts, p.Name)
}
if len(primaryPorts) == 1 {
// There is exactly one match in the set of preferred ports. Use
// this port, even if there may be others available. This allows
// flashing a specific board even if there are multiple available.
return primaryPorts[0], nil
} else if len(primaryPorts) > 1 {
// There are multiple preferred ports, probably because more than
// one device of the same type are connected (e.g. two Arduino
// Unos).
ports = primaryPorts
} else {
// No preferred ports found. Fall back to other serial ports
// available in the system.
ports = secondaryPorts
}
if len(ports) == 0 {
// fallback // fallback
switch runtime.GOOS { switch runtime.GOOS {
case "darwin": case "darwin":
@@ -929,6 +1009,7 @@ func main() {
gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, conservative)") gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, conservative)")
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)") panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
scheduler := flag.String("scheduler", "", "which scheduler to use (none, coroutines, tasks)") 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") printIR := flag.Bool("printir", false, "print LLVM IR")
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA") dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR") verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR")
@@ -938,7 +1019,7 @@ func main() {
printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines") 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") printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
printCommands := flag.Bool("x", false, "Print commands") 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)") 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") 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)") port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)")
@@ -947,10 +1028,11 @@ func main() {
wasmAbi := flag.String("wasm-abi", "", "WebAssembly ABI conventions: js (no i64 params) or generic") wasmAbi := flag.String("wasm-abi", "", "WebAssembly ABI conventions: js (no i64 params) or generic")
llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable") llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable")
var flagJSON, flagDeps *bool var flagJSON, flagDeps, flagTest *bool
if command == "help" || command == "list" { if command == "help" || command == "list" {
flagJSON = flag.Bool("json", false, "print data in JSON format") flagJSON = flag.Bool("json", false, "print data in JSON format")
flagDeps = flag.Bool("deps", false, "") flagDeps = flag.Bool("deps", false, "supply -deps flag to go list")
flagTest = flag.Bool("test", false, "supply -test flag to go list")
} }
var outpath string var outpath string
if command == "help" || command == "build" || command == "build-library" || command == "test" { if command == "help" || command == "build" || command == "build-library" || command == "test" {
@@ -1000,6 +1082,7 @@ func main() {
GC: *gc, GC: *gc,
PanicStrategy: *panicStrategy, PanicStrategy: *panicStrategy,
Scheduler: *scheduler, Scheduler: *scheduler,
Serial: *serial,
PrintIR: *printIR, PrintIR: *printIR,
DumpSSA: *dumpSSA, DumpSSA: *dumpSSA,
VerifyIR: *verifyIR, VerifyIR: *verifyIR,
@@ -1007,7 +1090,6 @@ func main() {
PrintSizes: *printSize, PrintSizes: *printSize,
PrintStacks: *printStacks, PrintStacks: *printStacks,
PrintAllocs: printAllocs, PrintAllocs: printAllocs,
PrintCommands: *printCommands,
Tags: *tags, Tags: *tags,
GlobalValues: globalVarValues, GlobalValues: globalVarValues,
WasmAbi: *wasmAbi, WasmAbi: *wasmAbi,
@@ -1015,6 +1097,9 @@ func main() {
OpenOCDCommands: ocdCommands, OpenOCDCommands: ocdCommands,
LLVMFeatures: *llvmFeatures, LLVMFeatures: *llvmFeatures,
} }
if *printCommands {
options.PrintCommands = printCommand
}
os.Setenv("CC", "clang -target="+*target) os.Setenv("CC", "clang -target="+*target)
@@ -1200,6 +1285,9 @@ func main() {
if *flagDeps { if *flagDeps {
extraArgs = append(extraArgs, "-deps") extraArgs = append(extraArgs, "-deps")
} }
if *flagTest {
extraArgs = append(extraArgs, "-test")
}
cmd, err := loader.List(config, extraArgs, flag.Args()) cmd, err := loader.List(config, extraArgs, flag.Args())
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "failed to run `go list`:", err) fmt.Fprintln(os.Stderr, "failed to run `go list`:", err)
+14 -15
View File
@@ -125,7 +125,7 @@ func TestCompiler(t *testing.T) {
// Test with few optimizations enabled (no inlining, etc). // Test with few optimizations enabled (no inlining, etc).
t.Run("opt=1", func(t *testing.T) { t.Run("opt=1", func(t *testing.T) {
t.Parallel() t.Parallel()
runTestWithConfig("stdlib.go", "", t, &compileopts.Options{ runTestWithConfig("stdlib.go", "", t, compileopts.Options{
Opt: "1", Opt: "1",
}, nil, nil) }, nil, nil)
}) })
@@ -134,15 +134,14 @@ func TestCompiler(t *testing.T) {
// TODO: fix this for stdlib.go, which currently fails. // TODO: fix this for stdlib.go, which currently fails.
t.Run("opt=0", func(t *testing.T) { t.Run("opt=0", func(t *testing.T) {
t.Parallel() t.Parallel()
runTestWithConfig("print.go", "", t, &compileopts.Options{ runTestWithConfig("print.go", "", t, compileopts.Options{
Opt: "0", Opt: "0",
}, nil, nil) }, nil, nil)
}) })
t.Run("ldflags", func(t *testing.T) { t.Run("ldflags", func(t *testing.T) {
t.Parallel() t.Parallel()
runTestWithConfig("ldflags.go", "", t, &compileopts.Options{ runTestWithConfig("ldflags.go", "", t, compileopts.Options{
Opt: "z",
GlobalValues: map[string]map[string]string{ GlobalValues: map[string]map[string]string{
"main": { "main": {
"someGlobal": "foobar", "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) { func runTest(name, target string, t *testing.T, cmdArgs, environmentVars []string) {
options := &compileopts.Options{ options := compileopts.Options{
Target: target, Target: target,
Opt: "z",
PrintIR: false,
DumpSSA: false,
VerifyIR: true,
Debug: true,
PrintSizes: "",
WasmAbi: "",
} }
runTestWithConfig(name, target, t, options, cmdArgs, environmentVars) 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. // Get the expected output for this test.
// Note: not using filepath.Join as it strips the path separator at the end // Note: not using filepath.Join as it strips the path separator at the end
// of the path. // of the path.
@@ -230,7 +229,7 @@ func runTestWithConfig(name, target string, t *testing.T, options *compileopts.O
// Build the test binary. // Build the test binary.
binary := filepath.Join(tmpdir, "test") binary := filepath.Join(tmpdir, "test")
err = runBuild("./"+path, binary, options) err = runBuild("./"+path, binary, &options)
if err != nil { if err != nil {
printCompilerError(t.Log, err) printCompilerError(t.Log, err)
t.Fail() t.Fail()
+19
View File
@@ -0,0 +1,19 @@
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package rand implements a cryptographically secure
// random number generator.
package rand
import "io"
// Reader is a global, shared instance of a cryptographically
// secure random number generator.
var Reader io.Reader
// Read is a helper function that calls Reader.Read using io.ReadFull.
// On return, n == len(b) if and only if err == nil.
func Read(b []byte) (n int, err error) {
return io.ReadFull(Reader, b)
}
+38
View File
@@ -0,0 +1,38 @@
// +build darwin freebsd wasi
// This implementation of crypto/rand uses the getentropy system call (available
// on both MacOS and WASI) to generate random numbers.
package rand
import (
"errors"
"unsafe"
)
var errReadFailed = errors.New("rand: could not read random bytes")
func init() {
Reader = &reader{}
}
type reader struct {
}
func (r *reader) Read(b []byte) (n int, err error) {
if len(b) != 0 {
if len(b) > 256 {
b = b[:256]
}
result := libc_getentropy(unsafe.Pointer(&b[0]), len(b))
if result < 0 {
// Maybe we should return a syscall.Errno here?
return 0, errReadFailed
}
}
return len(b), nil
}
// int getentropy(void *buf, size_t buflen);
//export getentropy
func libc_getentropy(buf unsafe.Pointer, buflen int) int
+38
View File
@@ -0,0 +1,38 @@
// +build linux,!baremetal,!wasi
// This implementation of crypto/rand uses the /dev/urandom pseudo-file to
// generate random numbers.
// TODO: convert to the getentropy or getrandom libc function on Linux once it
// is more widely supported.
package rand
import (
"syscall"
)
func init() {
Reader = &reader{}
}
type reader struct {
fd int
}
func (r *reader) Read(b []byte) (n int, err error) {
if len(b) == 0 {
return
}
// Open /dev/urandom first if needed.
if r.fd == 0 {
fd, err := syscall.Open("/dev/urandom", syscall.O_RDONLY, 0)
if err != nil {
return 0, err
}
r.fd = fd
}
// Read from the file.
return syscall.Read(r.fd, b)
}
+143
View File
@@ -0,0 +1,143 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package rand
import (
"errors"
"io"
"math/big"
)
// smallPrimes is a list of small, prime numbers that allows us to rapidly
// exclude some fraction of composite candidates when searching for a random
// prime. This list is truncated at the point where smallPrimesProduct exceeds
// a uint64. It does not include two because we ensure that the candidates are
// odd by construction.
var smallPrimes = []uint8{
3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53,
}
// smallPrimesProduct is the product of the values in smallPrimes and allows us
// to reduce a candidate prime by this number and then determine whether it's
// coprime to all the elements of smallPrimes without further big.Int
// operations.
var smallPrimesProduct = new(big.Int).SetUint64(16294579238595022365)
// Prime returns a number, p, of the given size, such that p is prime
// with high probability.
// Prime will return error for any error returned by rand.Read or if bits < 2.
func Prime(rand io.Reader, bits int) (p *big.Int, err error) {
if bits < 2 {
err = errors.New("crypto/rand: prime size must be at least 2-bit")
return
}
b := uint(bits % 8)
if b == 0 {
b = 8
}
bytes := make([]byte, (bits+7)/8)
p = new(big.Int)
bigMod := new(big.Int)
for {
_, err = io.ReadFull(rand, bytes)
if err != nil {
return nil, err
}
// Clear bits in the first byte to make sure the candidate has a size <= bits.
bytes[0] &= uint8(int(1<<b) - 1)
// Don't let the value be too small, i.e, set the most significant two bits.
// Setting the top two bits, rather than just the top bit,
// means that when two of these values are multiplied together,
// the result isn't ever one bit short.
if b >= 2 {
bytes[0] |= 3 << (b - 2)
} else {
// Here b==1, because b cannot be zero.
bytes[0] |= 1
if len(bytes) > 1 {
bytes[1] |= 0x80
}
}
// Make the value odd since an even number this large certainly isn't prime.
bytes[len(bytes)-1] |= 1
p.SetBytes(bytes)
// Calculate the value mod the product of smallPrimes. If it's
// a multiple of any of these primes we add two until it isn't.
// The probability of overflowing is minimal and can be ignored
// because we still perform Miller-Rabin tests on the result.
bigMod.Mod(p, smallPrimesProduct)
mod := bigMod.Uint64()
NextDelta:
for delta := uint64(0); delta < 1<<20; delta += 2 {
m := mod + delta
for _, prime := range smallPrimes {
if m%uint64(prime) == 0 && (bits > 6 || m != uint64(prime)) {
continue NextDelta
}
}
if delta > 0 {
bigMod.SetUint64(delta)
p.Add(p, bigMod)
}
break
}
// There is a tiny possibility that, by adding delta, we caused
// the number to be one bit too long. Thus we check BitLen
// here.
if p.ProbablyPrime(20) && p.BitLen() == bits {
return
}
}
}
// Int returns a uniform random value in [0, max). It panics if max <= 0.
func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
if max.Sign() <= 0 {
panic("crypto/rand: argument to Int is <= 0")
}
n = new(big.Int)
n.Sub(max, n.SetUint64(1))
// bitLen is the maximum bit length needed to encode a value < max.
bitLen := n.BitLen()
if bitLen == 0 {
// the only valid result is 0
return
}
// k is the maximum byte length needed to encode a value < max.
k := (bitLen + 7) / 8
// b is the number of bits in the most significant byte of max-1.
b := uint(bitLen % 8)
if b == 0 {
b = 8
}
bytes := make([]byte, k)
for {
_, err = io.ReadFull(rand, bytes)
if err != nil {
return nil, err
}
// Clear bits in the first byte to increase the probability
// that the candidate is < max.
bytes[0] &= uint8(int(1<<b) - 1)
n.SetBytes(bytes)
if n.Cmp(max) < 0 {
return
}
}
}
+32
View File
@@ -0,0 +1,32 @@
package main
import (
"math/rand"
"runtime"
"time"
)
func main() {
ms := runtime.MemStats{}
for {
escapesToHeap()
runtime.ReadMemStats(&ms)
println("Heap before GC. Used: ", ms.HeapInuse, " Free: ", ms.HeapIdle, " Meta: ", ms.GCSys)
runtime.GC()
runtime.ReadMemStats(&ms)
println("Heap after GC. Used: ", ms.HeapInuse, " Free: ", ms.HeapIdle, " Meta: ", ms.GCSys)
time.Sleep(5 * time.Second)
}
}
func escapesToHeap() {
n := rand.Intn(100)
println("Doing ", n, " iterations")
for i := 0; i < n; i++ {
s := make([]byte, i)
_ = append(s, 42)
}
}
+10
View File
@@ -0,0 +1,10 @@
// +build stm32
package main
import "machine"
const (
buttonMode = machine.PinInputPulldown
buttonPinChange = machine.PinRising | machine.PinFalling
)
+1 -1
View File
@@ -13,7 +13,7 @@ type Task struct {
Ptr unsafe.Pointer Ptr unsafe.Pointer
// Data is a field which can be used for storing state information. // Data is a field which can be used for storing state information.
Data uint Data uint64
// state is the underlying running state of the task. // state is the underlying running state of the task.
state state state state
-2
View File
@@ -47,8 +47,6 @@ const (
LED = D6 LED = D6
) )
var Serial = USB
// USBCDC pins // USBCDC pins
const ( const (
USBCDC_DM_PIN Pin = PA24 USBCDC_DM_PIN Pin = PA24
-2
View File
@@ -35,8 +35,6 @@ const (
LED3 Pin = PB03 // RX LED LED3 Pin = PB03 // RX LED
) )
var Serial = USB
// ADC pins // ADC pins
const ( const (
AREF Pin = PA03 AREF Pin = PA03
-2
View File
@@ -74,5 +74,3 @@ const (
PB30 Pin = 62 PB30 Pin = 62
PB31 Pin = 63 PB31 Pin = 63
) )
var Serial = USB
-2
View File
@@ -15,8 +15,6 @@ const (
BUTTON = PB31 BUTTON = PB31
) )
var Serial = USB
const ( const (
// https://ww1.microchip.com/downloads/en/DeviceDoc/70005321A.pdf // https://ww1.microchip.com/downloads/en/DeviceDoc/70005321A.pdf
+7 -1
View File
@@ -11,7 +11,13 @@ const (
LED = PC13 LED = PC13
) )
var Serial = UART1 const (
// This board does not have a user button, so
// use first GPIO pin by default
BUTTON = PA0
)
var DefaultUART = UART1
// UART pins // UART pins
const ( const (
+1 -2
View File
@@ -38,6 +38,7 @@ const (
const ( const (
LED = D13 LED = D13
NEOPIXELS = D8 NEOPIXELS = D8
WS2812 = D8
BUTTONA = D4 BUTTONA = D4
BUTTONB = D5 BUTTONB = D5
@@ -56,8 +57,6 @@ const (
UART_RX_PIN = P0_30 // PORTB UART_RX_PIN = P0_30 // PORTB
) )
var Serial = USB
// I2C pins // I2C pins
const ( const (
SDA_PIN = P0_05 // I2C0 external SDA_PIN = P0_05 // I2C0 external
+1
View File
@@ -41,6 +41,7 @@ const (
const ( const (
LED = D13 LED = D13
NEOPIXELS = D8 NEOPIXELS = D8
WS2812 = D8
BUTTONA = D4 BUTTONA = D4
BUTTONB = D5 BUTTONB = D5
+1 -5
View File
@@ -72,6 +72,7 @@ const (
LED1 = LED LED1 = LED
LED2 = D43 LED2 = D43
NEOPIXEL = D18 NEOPIXEL = D18
WS2812 = D18
BUTTON_LEFT = D5 BUTTON_LEFT = D5
BUTTON_RIGHT = D11 BUTTON_RIGHT = D11
@@ -103,11 +104,6 @@ const (
UART_TX_PIN = D1 UART_TX_PIN = D1
) )
// Serial is the USB device
var (
Serial = USB
)
// I2C pins // I2C pins
const ( const (
SDA_PIN = D20 // I2C0 external SDA_PIN = D20 // I2C0 external
-2
View File
@@ -68,8 +68,6 @@ const (
ADC3 Pin = IO39 ADC3 Pin = IO39
) )
var Serial = UART0
// UART0 pins // UART0 pins
const ( const (
UART_TX_PIN = IO1 UART_TX_PIN = IO1
+1 -2
View File
@@ -44,10 +44,9 @@ const (
const ( const (
LED = D13 LED = D13
NEOPIXELS = D8 NEOPIXELS = D8
WS2812 = D8
) )
var Serial = USB
// USBCDC pins // USBCDC pins
const ( const (
USBCDC_DM_PIN = PA24 USBCDC_DM_PIN = PA24
+2 -3
View File
@@ -36,11 +36,10 @@ const (
) )
const ( const (
LED = D13 LED = D13
WS2812 = D8
) )
var Serial = USB
// USBCDC pins // USBCDC pins
const ( const (
USBCDC_DM_PIN = PA24 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
)
+7 -7
View File
@@ -59,6 +59,7 @@ const (
LED1 = LED LED1 = LED
LED2 = D4 LED2 = D4
NEOPIXEL = D8 NEOPIXEL = D8
WS2812 = D8
BUTTON = D7 BUTTON = D7
QSPI_SCK = D27 QSPI_SCK = D27
@@ -71,13 +72,8 @@ const (
// UART0 pins (logical UART1) // UART0 pins (logical UART1)
const ( const (
UART_RX_PIN = D0 UART_RX_PIN = D1
UART_TX_PIN = D1 UART_TX_PIN = D0
)
// Serial is the USB device
var (
Serial = USB
) )
// I2C pins // I2C pins
@@ -103,3 +99,7 @@ var (
usb_VID uint16 = 0x239A usb_VID uint16 = 0x239A
usb_PID uint16 = 0x802A usb_PID uint16 = 0x802A
) )
var (
DefaultUART = UART0
)
+2 -1
View File
@@ -84,6 +84,7 @@ const (
LED_NEOPIXEL = D8 LED_NEOPIXEL = D8
LED_BUILTIN = LED_RED LED_BUILTIN = LED_RED
LED = LED_BUILTIN LED = LED_BUILTIN
WS2812 = D8
) )
func initLED() {} func initLED() {}
@@ -140,7 +141,7 @@ var (
TxAltFuncSelector: AF7_USART1_2_3, TxAltFuncSelector: AF7_USART1_2_3,
RxAltFuncSelector: AF7_USART1_2_3, RxAltFuncSelector: AF7_USART1_2_3,
} }
Serial = UART1 DefaultUART = UART1
) )
func initUART() { func initUART() {
+27
View File
@@ -0,0 +1,27 @@
// +build feather_rp2040
package machine
const (
LED = GPIO13
// 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
)
+1 -2
View File
@@ -139,10 +139,9 @@ const (
LED_RX = UART_RX_LED_PIN LED_RX = UART_RX_LED_PIN
LED_TX = UART_TX_LED_PIN LED_TX = UART_TX_LED_PIN
NEOPIXEL = NEOPIXEL_PIN NEOPIXEL = NEOPIXEL_PIN
WS2812 = NEOPIXEL_PIN
) )
var Serial = USB
// UART pins // UART pins
const ( const (
UART1_RX_PIN = D0 // (PB25) UART1_RX_PIN = D0 // (PB25)
+1 -1
View File
@@ -35,7 +35,7 @@ const (
LED_BLUE = P21 LED_BLUE = P21
) )
var Serial = UART0 var DefaultUART = UART0
const ( const (
// TODO: figure out the pin numbers for these. // TODO: figure out the pin numbers for these.
-2
View File
@@ -37,8 +37,6 @@ const (
LED = D13 LED = D13
) )
var Serial = USB
// USBCDC pins // USBCDC pins
const ( const (
USBCDC_DM_PIN = PA24 USBCDC_DM_PIN = PA24
-5
View File
@@ -70,11 +70,6 @@ const (
UART_TX_PIN = D1 UART_TX_PIN = D1
) )
// Serial is the USB device
var (
Serial = USB
)
// I2C pins // I2C pins
const ( const (
SDA_PIN = D21 // I2C0 external SDA_PIN = D21 // I2C0 external
+1 -1
View File
@@ -54,7 +54,7 @@ const (
I2C0_SDA_PIN = PA10 I2C0_SDA_PIN = PA10
) )
var Serial = UART0 var DefaultUART = UART0
var ( var (
+1 -1
View File
@@ -52,7 +52,7 @@ const (
LED_BLUE = D14 LED_BLUE = D14
) )
var Serial = UART0 var DefaultUART = UART0
// Default pins for UARTHS. // Default pins for UARTHS.
const ( const (
+1
View File
@@ -75,6 +75,7 @@ const (
const ( const (
LED = D13 LED = D13
NEOPIXEL = D4 NEOPIXEL = D4
WS2812 = D4
) )
// Button pins // Button pins
@@ -9,6 +9,7 @@ import (
// UART on the MatrixPortal M4 // UART on the MatrixPortal M4
var ( var (
Serial = UART1
UART1 = &_UART1 UART1 = &_UART1
_UART1 = UART{ _UART1 = UART{
Buffer: NewRingBuffer(), Buffer: NewRingBuffer(),
+2 -3
View File
@@ -37,11 +37,10 @@ const (
) )
const ( const (
LED = D13 LED = D13
WS2812 = D40
) )
var Serial = USB
// USBCDC pins // USBCDC pins
const ( const (
USBCDC_DM_PIN = PA24 USBCDC_DM_PIN = PA24
+1 -1
View File
@@ -12,7 +12,7 @@ const (
BUTTONB Pin = P11 BUTTONB Pin = P11
) )
var Serial = UART0 var DefaultUART = UART0
// UART pins // UART pins
const ( const (
+1 -1
View File
@@ -12,7 +12,7 @@ const (
BUTTONB Pin = 26 BUTTONB Pin = 26
) )
var Serial = UART0 var DefaultUART = UART0
// UART pins // UART pins
const ( const (
+95
View File
@@ -0,0 +1,95 @@
// +build nano_33_ble
// This contains the pin mappings for the Arduino Nano 33 BLE [Sense] boards.
//
// Flashing the board requires special version of bossac.
//
// This executable can be obtained two ways:
// 1) In Arduino IDE, install support for the board ("Arduino Mbed OS Nano Boards")
// Search for "tools/bossac/1.9.1-arduino2/bossac" in Arduino IDEs directory
// 2) Download https://downloads.arduino.cc/packages/package_index.json
// Search for "bossac-1.9.1-arduino2" in that file
// Download tarball for your OS and unpack it
//
// Once you have the executable, make it accessible in your PATH as "bossac_arduino2".
//
// It is possible to replace original bossac with this new one (this only adds support for nrf chip).
// In that case make "bossac_arduino2" symlink on it, for the board target to be able to find it.
//
// For more information, see:
// - https://store.arduino.cc/arduino-nano-33-ble
// - https://store.arduino.cc/arduino-nano-33-ble-sense
//
package machine
const HasLowFrequencyCrystal = true
// Digital Pins
const (
D2 Pin = P1_11
D3 Pin = P1_12
D4 Pin = P1_15
D5 Pin = P1_13
D6 Pin = P1_14
D7 Pin = P0_23
D8 Pin = P0_21
D9 Pin = P0_27
D10 Pin = P1_02
D11 Pin = P1_01
D12 Pin = P1_08
D13 Pin = P0_13
)
// Analog pins
const (
A0 Pin = P0_04
A1 Pin = P0_05
A2 Pin = P0_30
A3 Pin = P0_29
A4 Pin = P0_31
A5 Pin = P0_02
A6 Pin = P0_28
A7 Pin = P0_03
)
// Onboard LEDs
const (
LED = LED_BUILTIN
LED1 = LED_RED
LED2 = LED_GREEN
LED3 = LED_BLUE
LED_BUILTIN = P0_13
LED_RED = P0_24
LED_GREEN = P0_16
LED_BLUE = P0_06
)
// UART0 pins
const (
UART_RX_PIN = P1_10
UART_TX_PIN = P1_03
)
// I2C pins
const (
SDA_PIN = P0_31
SCL_PIN = P0_02
)
// SPI pins
const (
SPI0_SCK_PIN = P0_13
SPI0_SDO_PIN = P1_01
SPI0_SDI_PIN = P1_08
)
// USB CDC identifiers
const (
usb_STRING_PRODUCT = "Nano 33 BLE"
usb_STRING_MANUFACTURER = "Arduino"
)
var (
usb_VID uint16 = 0x2341
usb_PID uint16 = 0x805a
)
+98
View File
@@ -0,0 +1,98 @@
// +build nano_rp2040
// This contains the pin mappings for the Arduino Nano RP2040 Connect board.
//
// Sometimes the board is not detected even when the board is connected to your computer.
// To solve this, place a jumper wire between the REC and GND pins, then connect the board to your computer.
//
// For more information, see: https://store.arduino.cc/nano-rp2040-connect
// Also
// - Datasheets: https://docs.arduino.cc/hardware/nano-rp2040-connect
// - Nano RP2040 Connect technical reference: https://docs.arduino.cc/tutorials/nano-rp2040-connect/rp2040-01-technical-reference
//
package machine
// Digital Pins
const (
D2 Pin = GPIO25
D3 Pin = GPIO15
D4 Pin = GPIO16
D5 Pin = GPIO17
D6 Pin = GPIO18
D7 Pin = GPIO19
D8 Pin = GPIO20
D9 Pin = GPIO21
D10 Pin = GPIO5
D11 Pin = GPIO7
D12 Pin = GPIO4
D13 Pin = GPIO6
D14 Pin = GPIO26
D15 Pin = GPIO27
D16 Pin = GPIO28
D17 Pin = GPIO29
D18 Pin = GPIO12
D19 Pin = GPIO13
)
// Analog pins
const (
A0 Pin = ADC0
A1 Pin = ADC1
A2 Pin = ADC2
A3 Pin = ADC3
)
// Onboard LED
const (
LED = GPIO6
)
// I2C pins
const (
SDA_PIN Pin = GPIO12
SCL_PIN Pin = GPIO13
)
// 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
const (
NINA_SCK Pin = GPIO14
NINA_SDO Pin = GPIO11
NINA_SDI Pin = GPIO8
NINA_CS Pin = GPIO9
NINA_ACK Pin = GPIO10
NINA_GPIO0 Pin = GPIO0
NINA_RESETN Pin = GPIO3
NINA_TX Pin = GPIO9
NINA_RX Pin = GPIO8
)
// Onboard crystal oscillator frequency, in MHz.
const (
xoscFreq = 12 // MHz
)
// USB CDC identifiers
// https://github.com/arduino/ArduinoCore-mbed/blob/master/variants/NANO_RP2040_CONNECT/pins_arduino.h
const (
usb_STRING_PRODUCT = "Nano RP2040 Connect"
usb_STRING_MANUFACTURER = "Arduino"
)
var (
usb_VID uint16 = 0x2341
usb_PID uint16 = 0x005e
)
-5
View File
@@ -54,11 +54,6 @@ const (
UART_TX_PIN = P0_08 UART_TX_PIN = P0_08
) )
// Serial is the USB device
var (
Serial = USB
)
// I2C pins // I2C pins
const ( const (
SDA_PIN = P0_17 // I2C0 external SDA_PIN = P0_17 // I2C0 external
-2
View File
@@ -20,8 +20,6 @@ const (
// Onboard blue LED (on the AI-Thinker module). // Onboard blue LED (on the AI-Thinker module).
const LED = D4 const LED = D4
var Serial = UART0
// SPI pins // SPI pins
const ( const (
SPI0_SCK_PIN = D5 SPI0_SCK_PIN = D5
@@ -23,9 +23,6 @@ const (
UART_RX_PIN Pin = NoPin UART_RX_PIN Pin = NoPin
) )
// Serial is the USB device
var Serial = USB
// I2C pins (unused) // I2C pins (unused)
const ( const (
SDA_PIN = NoPin SDA_PIN = NoPin
-3
View File
@@ -18,9 +18,6 @@ const (
UART_RX_PIN Pin = 19 UART_RX_PIN Pin = 19
) )
// Serial is the USB device
var Serial = USB
// I2C pins (unused) // I2C pins (unused)
const ( const (
SDA_PIN = NoPin SDA_PIN = NoPin
+1 -1
View File
@@ -34,7 +34,7 @@ var (
Buffer: NewRingBuffer(), Buffer: NewRingBuffer(),
Bus: stm32.USART2, Bus: stm32.USART2,
} }
Serial = UART2 DefaultUART = UART2
) )
func init() { func init() {
+1 -1
View File
@@ -38,7 +38,7 @@ var (
TxAltFuncSelector: UART_ALT_FN, TxAltFuncSelector: UART_ALT_FN,
RxAltFuncSelector: UART_ALT_FN, RxAltFuncSelector: UART_ALT_FN,
} }
Serial = UART1 DefaultUART = UART1
) )
func init() { func init() {
+7 -1
View File
@@ -13,6 +13,12 @@ const (
LED_GREEN = PB3 LED_GREEN = PB3
) )
const (
// This board does not have a user button, so
// use first GPIO pin by default
BUTTON = PA0
)
const ( const (
// Arduino Pins // Arduino Pins
A0 = PA0 // ADC_IN0 A0 = PA0 // ADC_IN0
@@ -70,7 +76,7 @@ var (
TxAltFuncSelector: 4, TxAltFuncSelector: 4,
RxAltFuncSelector: 4, RxAltFuncSelector: 4,
} }
Serial = UART1 DefaultUART = UART1
// I2C1 is documented, alias to I2C0 as well // I2C1 is documented, alias to I2C0 as well
I2C1 = &I2C{ I2C1 = &I2C{
+7 -1
View File
@@ -13,6 +13,12 @@ const (
LED_GREEN = PB3 LED_GREEN = PB3
) )
const (
// This board does not have a user button, so
// use first GPIO pin by default
BUTTON = PA0
)
const ( const (
// Arduino Pins // Arduino Pins
A0 = PA0 A0 = PA0
@@ -72,7 +78,7 @@ var (
TxAltFuncSelector: 7, TxAltFuncSelector: 7,
RxAltFuncSelector: 3, RxAltFuncSelector: 3,
} }
Serial = UART1 DefaultUART = UART1
// I2C1 is documented, alias to I2C0 as well // I2C1 is documented, alias to I2C0 as well
I2C1 = &I2C{ I2C1 = &I2C{
+1 -1
View File
@@ -38,7 +38,7 @@ var (
TxAltFuncSelector: UART_ALT_FN, TxAltFuncSelector: UART_ALT_FN,
RxAltFuncSelector: UART_ALT_FN, RxAltFuncSelector: UART_ALT_FN,
} }
Serial = UART1 DefaultUART = UART1
) )
const ( const (
+1 -1
View File
@@ -41,7 +41,7 @@ const (
// UART // UART
var ( var (
Serial = UART0 DefaultUART = UART0
) )
const ( const (
+1 -1
View File
@@ -41,7 +41,7 @@ const (
// UART // UART
var ( var (
Serial = UART0 DefaultUART = UART0
) )
const ( const (
+1 -1
View File
@@ -41,7 +41,7 @@ const (
// UART // UART
var ( var (
Serial = UART0 DefaultUART = UART0
) )
const ( const (
+1 -1
View File
@@ -19,7 +19,7 @@ const (
LED_BLUE Pin = 23 LED_BLUE Pin = 23
) )
var Serial = UART0 var DefaultUART = UART0
// UART pins // UART pins
const ( const (
+1 -1
View File
@@ -23,7 +23,7 @@ const (
BUTTON4 Pin = 16 BUTTON4 Pin = 16
) )
var Serial = UART0 var DefaultUART = UART0
// UART pins for NRF52840-DK // UART pins for NRF52840-DK
const ( const (
+1 -1
View File
@@ -22,7 +22,7 @@ const (
BUTTON4 Pin = 25 BUTTON4 Pin = 25
) )
var Serial = UART0 var DefaultUART = UART0
// UART pins // UART pins
const ( const (
-5
View File
@@ -34,11 +34,6 @@ const (
UART_RX_PIN Pin = NoPin UART_RX_PIN Pin = NoPin
) )
// Serial is the USB device
var (
Serial = USB
)
// I2C pins (unused) // I2C pins (unused)
const ( const (
SDA_PIN = NoPin SDA_PIN = NoPin
+44 -31
View File
@@ -4,40 +4,53 @@ package machine
// GPIO pins // GPIO pins
const ( const (
GP0 Pin = 0 GP0 Pin = GPIO0
GP1 Pin = 1 GP1 Pin = GPIO1
GP2 Pin = 2 GP2 Pin = GPIO2
GP3 Pin = 3 GP3 Pin = GPIO3
GP4 Pin = 4 GP4 Pin = GPIO4
GP5 Pin = 5 GP5 Pin = GPIO5
GP6 Pin = 6 GP6 Pin = GPIO6
GP7 Pin = 7 GP7 Pin = GPIO7
GP8 Pin = 8 GP8 Pin = GPIO8
GP9 Pin = 9 GP9 Pin = GPIO9
GP10 Pin = 10 GP10 Pin = GPIO10
GP11 Pin = 11 GP11 Pin = GPIO11
GP12 Pin = 12 GP12 Pin = GPIO12
GP13 Pin = 13 GP13 Pin = GPIO13
GP14 Pin = 14 GP14 Pin = GPIO14
GP15 Pin = 15 GP15 Pin = GPIO15
GP16 Pin = 16 GP16 Pin = GPIO16
GP17 Pin = 17 GP17 Pin = GPIO17
GP18 Pin = 18 GP18 Pin = GPIO18
GP19 Pin = 19 GP19 Pin = GPIO19
GP20 Pin = 20 GP20 Pin = GPIO20
GP21 Pin = 21 GP21 Pin = GPIO21
GP22 Pin = 22 GP22 Pin = GPIO22
GP23 Pin = 23 GP26 Pin = GPIO26
GP24 Pin = 24 GP27 Pin = GPIO27
GP25 Pin = 25 GP28 Pin = GPIO28
GP26 Pin = 26
GP27 Pin = 27
GP28 Pin = 28
GP29 Pin = 29
// Onboard LED // Onboard LED
LED Pin = GP25 LED Pin = GPIO25
// Onboard crystal oscillator frequency, in MHz. // Onboard crystal oscillator frequency, in MHz.
xoscFreq = 12 // 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 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 // UART pins for PineTime. Note that RX is set to NoPin as RXD is not listed in
// the PineTime schematic 1.0: // the PineTime schematic 1.0:
+1 -2
View File
@@ -40,6 +40,7 @@ const (
const ( const (
LED = D13 LED = D13
NEOPIXELS = D8 NEOPIXELS = D8
WS2812 = D8
LIGHTSENSOR = A7 LIGHTSENSOR = A7
@@ -66,8 +67,6 @@ const (
BUTTON_B_MASK = 128 BUTTON_B_MASK = 128
) )
var Serial = USB
// USBCDC pins // USBCDC pins
const ( const (
USBCDC_DM_PIN = PA24 USBCDC_DM_PIN = PA24
+1 -2
View File
@@ -42,6 +42,7 @@ const (
const ( const (
LED = D13 LED = D13
NEOPIXELS = D8 NEOPIXELS = D8
WS2812 = D8
SD_CS = D7 SD_CS = D7
@@ -69,8 +70,6 @@ const (
BUTTON_B_MASK = 128 BUTTON_B_MASK = 128
) )
var Serial = USB
// USBCDC pins // USBCDC pins
const ( const (
USBCDC_DM_PIN = PA24 USBCDC_DM_PIN = PA24
+1 -2
View File
@@ -68,6 +68,7 @@ const (
TFT_WR = D26 TFT_WR = D26
NEOPIXEL = D2 NEOPIXEL = D2
WS2812 = D2
SPK_SD = D50 SPK_SD = D50
) )
@@ -94,8 +95,6 @@ const (
LED = D13 LED = D13
) )
var Serial = USB
// USBCDC pins // USBCDC pins
const ( const (
USBCDC_DM_PIN = PA24 USBCDC_DM_PIN = PA24
+3 -1
View File
@@ -42,7 +42,9 @@ const (
) )
const ( const (
LED = D13 NEOPIXELS = D11
WS2812 = D11
NEOPIXELS_POWER = D12
) )
// USBCDC pins // USBCDC pins
+1 -1
View File
@@ -29,7 +29,7 @@ const (
BUTTON Pin = 7 BUTTON Pin = 7
) )
var Serial = UART0 var DefaultUART = UART0
// UART pins // UART pins
const ( const (
+5 -1
View File
@@ -20,6 +20,10 @@ const (
LED_BLUE = PD15 LED_BLUE = PD15
) )
const (
BUTTON = PA0
)
// UART pins // UART pins
const ( const (
UART_TX_PIN = PA2 UART_TX_PIN = PA2
@@ -34,7 +38,7 @@ var (
TxAltFuncSelector: AF7_USART1_2_3, TxAltFuncSelector: AF7_USART1_2_3,
RxAltFuncSelector: 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 // set up RX IRQ handler. Follow similar pattern for other UARTx instances
+2
View File
@@ -87,6 +87,8 @@ var (
TeensyUART5 = UART4 TeensyUART5 = UART4
) )
var DefaultUART = UART0
const ( const (
defaultUART0RX = D00 defaultUART0RX = D00
defaultUART0TX = D01 defaultUART0TX = D01
+3 -3
View File
@@ -146,9 +146,9 @@ const (
) )
var ( var (
Serial = UART1 DefaultUART = UART1
UART1 = &_UART1 UART1 = &_UART1
_UART1 = UART{ _UART1 = UART{
Bus: nxp.LPUART6, Bus: nxp.LPUART6,
Buffer: NewRingBuffer(), Buffer: NewRingBuffer(),
txBuffer: NewRingBuffer(), txBuffer: NewRingBuffer(),
-2
View File
@@ -325,8 +325,6 @@ const (
OUTPUT_CTR_3V3 = PC15 OUTPUT_CTR_3V3 = PC15
) )
var Serial = USB
// USBCDC pins // USBCDC pins
const ( const (
USBCDC_DM_PIN = PIN_USB_DM USBCDC_DM_PIN = PIN_USB_DM
+1 -1
View File
@@ -27,4 +27,4 @@ const (
const HasLowFrequencyCrystal = true 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. // Always use UART0 as the serial output.
var Serial = UART0 var DefaultUART = UART0
// UART // UART
var ( var (
+2
View File
@@ -251,6 +251,8 @@ func (p Pin) mux() *volatile.Register32 {
} }
} }
var DefaultUART = UART0
var ( var (
UART0 = &_UART0 UART0 = &_UART0
_UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()} _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 return &esp.GPIO.GPIO_OUT_W1TC.Reg, 1 << p
} }
var DefaultUART = UART0
// UART0 is a hardware UART that supports both TX and RX. // UART0 is a hardware UART that supports both TX and RX.
var UART0 = &_UART0 var UART0 = &_UART0
var _UART0 = UART{Buffer: NewRingBuffer()} var _UART0 = UART{Buffer: NewRingBuffer()}
+6 -6
View File
@@ -11,6 +11,12 @@ var (
USB = &UART{100} 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 ( const (
PinInput PinMode = iota PinInput PinMode = iota
PinOutput PinOutput
@@ -118,12 +124,6 @@ type UART struct {
Bus uint8 Bus uint8
} }
type UARTConfig struct {
BaudRate uint32
TX Pin
RX Pin
}
// Configure the UART. // Configure the UART.
func (uart *UART) Configure(config UARTConfig) { func (uart *UART) Configure(config UARTConfig) {
uartConfigure(uart.Bus, config.TX, config.RX) uartConfigure(uart.Bus, config.TX, config.RX)

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