Compare commits

..

1 Commits

Author SHA1 Message Date
Ayke van Laethem 22b5b69cf0 WIP alpine build 2021-11-16 21:57:51 +01:00
16 changed files with 205 additions and 344 deletions
+60 -41
View File
@@ -163,17 +163,20 @@ commands:
command: | command: |
sudo apt-get update sudo apt-get update
sudo apt-get install --no-install-recommends \ sudo apt-get install --no-install-recommends \
libgnutls30 libssl1.0.2 \
qemu-system-arm \ qemu-system-arm \
qemu-system-riscv32 \
qemu-user \ qemu-user \
gcc-avr \ gcc-avr \
avr-libc \ avr-libc \
ninja-build \ ninja-build \
python3 python3
- install-node - install-node
- install-chrome
- install-wasmtime - install-wasmtime
- install-cmake - install-cmake
- hack-ninja-jobs - hack-ninja-jobs
- install-xtensa-toolchain:
variant: "linux-amd64"
- restore_cache: - restore_cache:
keys: keys:
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }} - go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
@@ -198,7 +201,12 @@ commands:
key: llvm-build-11-linux-v4-assert key: llvm-build-11-linux-v4-assert
paths: paths:
llvm-build llvm-build
- build-binaryen-linux - build-binaryen-linux-stretch
- run:
name: "Build TinyGo"
command: |
make ASSERT=1
echo 'export PATH=$(pwd)/build:$PATH' >> $BASH_ENV
- build-wasi-libc - build-wasi-libc
- run: - run:
name: "Test TinyGo" name: "Test TinyGo"
@@ -209,63 +217,73 @@ commands:
# necessary to keep memory consumption down and avoid OOM (for a # necessary to keep memory consumption down and avoid OOM (for a
# 2CPU/4GB executor). # 2CPU/4GB executor).
GOFLAGS: -p=2 GOFLAGS: -p=2
- run:
name: "Build TinyGo"
command: |
make ASSERT=1
echo 'export PATH=$(pwd)/build:$PATH' >> $BASH_ENV
- run: make tinygo-test
- save_cache: - save_cache:
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }} key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths: paths:
- ~/.cache/go-build - ~/.cache/go-build
- /go/pkg/mod - /go/pkg/mod
- install-xtensa-toolchain:
variant: "linux-amd64"
- run: make gen-device -j4 - run: make gen-device -j4
- run: make smoketest - run: make smoketest
- install-chrome - run: make tinygo-test
- run: make wasmtest - run: make wasmtest
build-linux: build-linux:
steps: steps:
- checkout
- submodules
- run: - run:
name: "Install apt dependencies" name: "Install apk dependencies"
command: | command: |
sudo apt-get update apk add git openssh make g++ gcompat
sudo apt-get install --no-install-recommends \ - checkout
libgnutls30 libssl1.0.2 \ - run:
ninja-build \ name: "Install Go"
python3 command: |
- install-cmake wget https://dl.google.com/go/go1.17.3.linux-amd64.tar.gz
- hack-ninja-jobs tar -C /usr/local -xzf go1.17.3.linux-amd64.tar.gz
ln -s /usr/local/go/bin/go /usr/local/bin/go
#- submodules
- restore_cache: - restore_cache:
name: "Restore Go cache"
keys: keys:
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }} - go-cache-alpine-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-v2-{{ checksum "go.mod" }} - go-cache-alpine-v2-{{ checksum "go.mod" }}
- llvm-source-linux
- restore_cache: - restore_cache:
name: "Restore llvm-source cache"
keys: keys:
- llvm-build-11-linux-v4-noassert - llvm-source-11-alpine-v2-x0
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
name: "Save llvm-source cache"
key: llvm-source-11-alpine-v2-x0
paths:
- llvm-project
#- llvm-project/clang/lib/Headers
#- llvm-project/clang/include
#- llvm-project/lld/include
#- llvm-project/llvm/include
- restore_cache:
name: "Restore llvm-build cache"
keys:
- llvm-build-11-alpine-v1-noassert-x0
- run: - run:
name: "Build LLVM" name: "Build LLVM"
command: | command: |
if [ ! -f llvm-build/lib/liblldELF.a ] if [ ! -f llvm-build/lib/liblldELF.a ]
then then
# fetch LLVM source (may only have headers right now) # fetch LLVM source (may only have headers right now)
rm -rf llvm-project #rm -rf llvm-project
make llvm-source #make llvm-source
# install dependencies
apk add cmake samurai python3
# build! # build!
make llvm-build SAMUFLAGS=-j3 make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \; #find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
fi fi
- save_cache: - save_cache:
key: llvm-build-11-linux-v4-noassert name: "Save llvm-build cache"
key: llvm-build-11-alpine-v1-noassert-x0
paths: paths:
llvm-build llvm-build
- build-binaryen-linux-stretch
- build-wasi-libc
- run: - run:
name: "Install fpm" name: "Install fpm"
command: | command: |
@@ -286,7 +304,8 @@ commands:
- store_artifacts: - store_artifacts:
path: /tmp/tinygo_amd64.deb path: /tmp/tinygo_amd64.deb
- save_cache: - save_cache:
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }} name: "Save Go cache"
key: go-cache-alpine-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths: paths:
- ~/.cache/go-build - ~/.cache/go-build
- /go/pkg/mod - /go/pkg/mod
@@ -323,7 +342,7 @@ commands:
curl https://dl.google.com/go/go1.17.darwin-amd64.tar.gz -o go1.17.darwin-amd64.tar.gz curl https://dl.google.com/go/go1.17.darwin-amd64.tar.gz -o go1.17.darwin-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.17.darwin-amd64.tar.gz sudo tar -C /usr/local -xzf go1.17.darwin-amd64.tar.gz
ln -s /usr/local/go/bin/go /usr/local/bin/go ln -s /usr/local/go/bin/go /usr/local/bin/go
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake ninja HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu cmake ninja
- install-xtensa-toolchain: - install-xtensa-toolchain:
variant: "macos" variant: "macos"
- restore_cache: - restore_cache:
@@ -388,7 +407,7 @@ commands:
- lib/wasi-libc/sysroot - lib/wasi-libc/sysroot
- run: - run:
name: "Test TinyGo" name: "Test TinyGo"
command: make test GOTESTFLAGS="-v -short" command: make test
no_output_timeout: 20m no_output_timeout: 20m
- run: - run:
name: "Build TinyGo release" name: "Build TinyGo release"
@@ -426,12 +445,12 @@ jobs:
llvm: "11" llvm: "11"
assert-test-linux: assert-test-linux:
docker: docker:
- image: circleci/golang:1.17-buster - image: circleci/golang:1.17-stretch
steps: steps:
- assert-test-linux - assert-test-linux
build-linux: build-linux:
docker: docker:
- image: circleci/golang:1.17-stretch - image: alpine:3.14
steps: steps:
- build-linux - build-linux
test-linux-build: test-linux-build:
@@ -450,11 +469,11 @@ jobs:
workflows: workflows:
test-all: test-all:
jobs: jobs:
- test-llvm11-go115 #- test-llvm11-go115
- test-llvm11-go116 #- test-llvm11-go116
- build-linux - build-linux
- test-linux-build: - test-linux-build:
requires: requires:
- build-linux - build-linux
- build-macos #- build-macos
- assert-test-linux #- assert-test-linux
+7 -2
View File
@@ -1,7 +1,7 @@
name: Windows name: Windows
on: on:
pull_request: #pull_request:
push: push:
branches: branches:
- dev - dev
@@ -15,6 +15,11 @@ jobs:
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
go-version: '1.17' go-version: '1.17'
- name: Install QEMU
shell: bash
run: |
choco install qemu --version=2020.06.12
echo "C:\Program Files\QEMU" >> $GITHUB_PATH
- name: Install Ninja - name: Install Ninja
shell: bash shell: bash
run: | run: |
@@ -73,7 +78,7 @@ jobs:
run: make binaryen run: make binaryen
- name: Test TinyGo - name: Test TinyGo
shell: bash shell: bash
run: make test GOTESTFLAGS="-v -short" run: make test
- name: Build TinyGo release tarball - name: Build TinyGo release tarball
run: make build/release -j4 run: make build/release -j4
- name: Make release artifact - name: Make release artifact
-94
View File
@@ -1,97 +1,3 @@
0.21.0
---
* **command line**
- drop support for LLVM 10
- `build`: drop support for LLVM targets in the -target flag
- `build`: fix paths in error messages on Windows
- `build`: add -p flag to set parallelism
- `lldb`: implement `tinygo lldb` subcommand
- `test`: use emulator exit code instead of parsing test output
- `test`: pass testing arguments to wasmtime
* **compiler**
- use -opt flag for optimization level in CFlags (-Os, etc)
- `builder`: improve accuracy of the -size=full flag
- `builder`: hardcode some more frame sizes for __aeabi_* functions
- `builder`: add support for -size= flag for WebAssembly
- `cgo`: fix line/column reporting in syntax error messages
- `cgo`: support function definitions in CGo headers
- `cgo`: implement rudimentary C array decaying
- `cgo`: add support for stdio in picolibc and wasi-libc
- `cgo`: run CGo parser per file, not per CGo fragment
- `compiler`: fix unintentionally exported math functions
- `compiler`: properly implement div and rem operations
- `compiler`: add support for recursive function types
- `compiler`: add support for the `go` keyword on interface methods
- `compiler`: add minsize attribute for -Oz
- `compiler`: add "target-cpu" and "target-features" attributes
- `compiler`: fix indices into strings and arrays
- `compiler`: fix string compare functions
- `interp`: simplify some code to avoid some errors
- `interp`: support recursive globals (like linked lists) in globals
- `interp`: support constant globals
- `interp`: fix reverting of extractvalue/insertvalue with multiple indices
- `transform`: work around renamed return type after merging LLVM modules
* **standard library**
- `internal/bytealg`: fix indexing error in Compare()
- `machine`: support Pin.Get() function when the pin is configured as output
- `net`, `syscall`: Reduce code duplication by switching to internal/itoa.
- `os`: don't try to read executable path on baremetal
- `os`: implement Getwd
- `os`: add File.WriteString and File.WriteAt
- `reflect`: fix type.Size() to account for struct padding
- `reflect`: don't construct an interface-in-interface value
- `reflect`: implement Value.Elem() for interface values
- `reflect`: fix Value.Index() in a specific case
- `reflect`: add support for DeepEqual
- `runtime`: add another set of invalid unicode runes to encodeUTF8()
- `runtime`: only initialize os.runtime_args when needed
- `runtime`: only use CRLF on baremetal systems for println
- `runtime/debug`: stub `debug.SetMaxStack`
- `runtime/debug`: stub `debug.Stack`
- `testing`: add a stub for t.Parallel()
- `testing`: add support for -test.short flag
- `testing`: stub B.ReportAllocs()
- `testing`: add `testing.Verbose`
- `testing`: stub `testing.AllocsPerRun`
* **targets**
- fix gen-device-svd to handle 64-bit values
- add CPU and Features property to all targets
- match LLVM triple to the one Clang uses
- `atsam`: simplify definition of SERCOM UART, I2C and SPI peripherals
- `atsam`: move I2S0 to machine file
- `esp32`: fix SPI configuration
- `esp32c3`: add support for GDB debugging
- `esp32c3`: add support for CPU interrupts
- `esp32c3`: use tasks scheduler by default
- `fe310`: increase CPU frequency from 16MHz to 320MHz
- `fe310`: add support for bit banging drivers
- `linux`: build static binaries using musl
- `linux`: reduce binary size by calling `write` instead of `putchar`
- `linux`: add support for GOARM
- `riscv`: implement 32-bit atomic operations
- `riscv`: align the heap to 16 bytes
- `riscv`: switch to tasks-based scheduler
- `rp2040`: add CPUFrequency()
- `rp2040`: improve I2C baud rate configuration
- `rp2040`: add pin interrupt API
- `rp2040`: refactor PWM code and fix Period calculation
- `stm32f103`: fix SPI
- `stm32f103`: make SPI frequency selection more flexible
- `qemu`: signal correct exit code to QEMU
- `wasi`: run C/C++ constructors at startup
- `wasm`: ensure heapptr is aligned
- `wasm`: update wasi-libc dependency
- `wasm`: wasi: use asyncify
- `wasm`: support `-scheduler=none`
- `windows`: add support for Windows (amd64 only for now)
* **boards**
- `feather-stm32f405`, `feather-rp2040`: add I2C pin names
- `m5stack-core2`: add M5Stack Core2
- `nano-33-ble`: SoftDevice s140v7 support
- `nano-33-ble`: add constants for more on-board pins
0.20.0 0.20.0
--- ---
+3 -6
View File
@@ -18,9 +18,6 @@ LLVM_NM ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-nm))$(call detec
GO ?= go GO ?= go
export GOROOT = $(shell $(GO) env GOROOT) export GOROOT = $(shell $(GO) env GOROOT)
# Flags to pass to go test.
GOTESTFLAGS ?= -v
# md5sum binary # md5sum binary
MD5SUM = md5sum MD5SUM = md5sum
@@ -171,8 +168,8 @@ $(LLVM_BUILDDIR)/build.ninja: llvm-source
mkdir -p $(LLVM_BUILDDIR) && cd $(LLVM_BUILDDIR) && cmake -G Ninja $(TINYGO_SOURCE_DIR)/$(LLVM_PROJECTDIR)/llvm "-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=AVR;Xtensa" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_LIBEDIT=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_ENABLE_OCAMLDOC=OFF -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF -DCLANG_ENABLE_ARCMT=OFF $(LLVM_OPTION) mkdir -p $(LLVM_BUILDDIR) && cd $(LLVM_BUILDDIR) && cmake -G Ninja $(TINYGO_SOURCE_DIR)/$(LLVM_PROJECTDIR)/llvm "-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=AVR;Xtensa" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_LIBEDIT=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_ENABLE_OCAMLDOC=OFF -DLLVM_ENABLE_LIBXML2=OFF -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD=OFF -DCLANG_ENABLE_STATIC_ANALYZER=OFF -DCLANG_ENABLE_ARCMT=OFF $(LLVM_OPTION)
# Build LLVM. # Build LLVM.
$(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja $(LLVM_BUILDDIR): #$(LLVM_BUILDDIR)/build.ninja
cd $(LLVM_BUILDDIR) && ninja $(NINJA_BUILD_TARGETS) cd $(LLVM_BUILDDIR) && ninja llvm-nm #$(NINJA_BUILD_TARGETS)
# Build Binaryen # Build Binaryen
.PHONY: binaryen .PHONY: binaryen
@@ -195,7 +192,7 @@ tinygo:
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X main.gitSha1=`git rev-parse --short HEAD`" . CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X main.gitSha1=`git rev-parse --short HEAD`" .
test: wasi-libc test: wasi-libc
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags byollvm ./builder ./cgo ./compileopts ./compiler ./interp ./transform . CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test -v -timeout=20m -buildmode exe -tags byollvm ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
TEST_PACKAGES = \ TEST_PACKAGES = \
compress/bzip2 \ compress/bzip2 \
+5 -5
View File
@@ -2276,16 +2276,16 @@ func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Va
case token.NEQ: // != case token.NEQ: // !=
result := b.createRuntimeCall("stringEqual", []llvm.Value{x, y}, "") result := b.createRuntimeCall("stringEqual", []llvm.Value{x, y}, "")
return b.CreateNot(result, ""), nil return b.CreateNot(result, ""), nil
case token.LSS: // x < y case token.LSS: // <
return b.createRuntimeCall("stringLess", []llvm.Value{x, y}, ""), nil return b.createRuntimeCall("stringLess", []llvm.Value{x, y}, ""), nil
case token.LEQ: // x <= y becomes NOT (y < x) case token.LEQ: // <=
result := b.createRuntimeCall("stringLess", []llvm.Value{y, x}, "") result := b.createRuntimeCall("stringLess", []llvm.Value{y, x}, "")
return b.CreateNot(result, ""), nil return b.CreateNot(result, ""), nil
case token.GTR: // x > y becomes y < x case token.GTR: // >
return b.createRuntimeCall("stringLess", []llvm.Value{y, x}, ""), nil
case token.GEQ: // x >= y becomes NOT (x < y)
result := b.createRuntimeCall("stringLess", []llvm.Value{x, y}, "") result := b.createRuntimeCall("stringLess", []llvm.Value{x, y}, "")
return b.CreateNot(result, ""), nil return b.CreateNot(result, ""), nil
case token.GEQ: // >=
return b.createRuntimeCall("stringLess", []llvm.Value{y, x}, ""), nil
default: default:
panic("binop on string: " + op.String()) panic("binop on string: " + op.String())
} }
+3 -2
View File
@@ -71,8 +71,9 @@ entry:
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden i1 @main.stringCompareLarger(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr #0 { define hidden i1 @main.stringCompareLarger(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr #0 {
entry: entry:
%0 = call i1 @runtime.stringLess(i8* %s2.data, i32 %s2.len, i8* %s1.data, i32 %s1.len, i8* undef, i8* null) #0 %0 = call i1 @runtime.stringLess(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null) #0
ret i1 %0 %1 = xor i1 %0, true
ret i1 %1
} }
declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*, i8*) declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*, i8*)
+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.21.0" const Version = "0.21.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.
+35 -33
View File
@@ -75,6 +75,40 @@ func TestCompiler(t *testing.T) {
runPlatTests(optionsFromTarget(""), tests, t) runPlatTests(optionsFromTarget(""), tests, t)
}) })
if testing.Short() {
return
}
t.Run("EmulatedCortexM3", func(t *testing.T) {
runPlatTests(optionsFromTarget("cortex-m-qemu"), tests, t)
})
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
// Note: running only on Windows and macOS because Linux (as of 2020)
// usually has an outdated QEMU version that doesn't support RISC-V yet.
t.Run("EmulatedRISCV", func(t *testing.T) {
runPlatTests(optionsFromTarget("riscv-qemu"), tests, t)
})
}
if runtime.GOOS == "linux" {
t.Run("X86Linux", func(t *testing.T) {
runPlatTests(optionsFromOSARCH("linux/386"), tests, t)
})
t.Run("ARMLinux", func(t *testing.T) {
runPlatTests(optionsFromOSARCH("linux/arm/6"), tests, t)
})
t.Run("ARM64Linux", func(t *testing.T) {
runPlatTests(optionsFromOSARCH("linux/arm64"), tests, t)
})
t.Run("WebAssembly", func(t *testing.T) {
runPlatTests(optionsFromTarget("wasm"), tests, t)
})
t.Run("WASI", func(t *testing.T) {
runPlatTests(optionsFromTarget("wasi"), tests, t)
})
}
// Test a few build options. // Test a few build options.
t.Run("build-options", func(t *testing.T) { t.Run("build-options", func(t *testing.T) {
t.Parallel() t.Parallel()
@@ -116,38 +150,6 @@ func TestCompiler(t *testing.T) {
}, nil, nil) }, nil, nil)
}) })
}) })
if testing.Short() {
// Don't test other targets when the -short flag is used. Only test the
// host system.
return
}
t.Run("EmulatedCortexM3", func(t *testing.T) {
runPlatTests(optionsFromTarget("cortex-m-qemu"), tests, t)
})
t.Run("EmulatedRISCV", func(t *testing.T) {
runPlatTests(optionsFromTarget("riscv-qemu"), tests, t)
})
if runtime.GOOS == "linux" {
t.Run("X86Linux", func(t *testing.T) {
runPlatTests(optionsFromOSARCH("linux/386"), tests, t)
})
t.Run("ARMLinux", func(t *testing.T) {
runPlatTests(optionsFromOSARCH("linux/arm/6"), tests, t)
})
t.Run("ARM64Linux", func(t *testing.T) {
runPlatTests(optionsFromOSARCH("linux/arm64"), tests, t)
})
t.Run("WebAssembly", func(t *testing.T) {
runPlatTests(optionsFromTarget("wasm"), tests, t)
})
t.Run("WASI", func(t *testing.T) {
runPlatTests(optionsFromTarget("wasi"), tests, t)
})
}
} }
func runPlatTests(options compileopts.Options, tests []string, t *testing.T) { func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
@@ -164,7 +166,7 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
t.Parallel() t.Parallel()
runTest("env.go", options, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"}) runTest("env.go", options, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
}) })
if options.Target == "wasi" || options.Target == "wasm" { if options.Target == "wasi" {
t.Run("alias.go-scheduler-none", func(t *testing.T) { t.Run("alias.go-scheduler-none", func(t *testing.T) {
t.Parallel() t.Parallel()
options := compileopts.Options(options) options := compileopts.Options(options)
-6
View File
@@ -18,12 +18,6 @@ func CPUFrequency() uint32 {
return 125 * MHz return 125 * MHz
} }
// Returns the period of a clock cycle for the raspberry pi pico in nanoseconds.
// Used in PWM API.
func cpuPeriod() uint32 {
return 1e9 / CPUFrequency()
}
// clockIndex identifies a hardware clock // clockIndex identifies a hardware clock
type clockIndex uint8 type clockIndex uint8
+63 -77
View File
@@ -1,4 +1,3 @@
//go:build rp2040
// +build rp2040 // +build rp2040
package machine package machine
@@ -6,13 +5,12 @@ package machine
import ( import (
"device/rp" "device/rp"
"errors" "errors"
"math"
"runtime/volatile" "runtime/volatile"
"unsafe" "unsafe"
) )
var ( var (
ErrBadPeriod = errors.New("period outside valid range 8ns..268ms") ErrPeriodTooBig = errors.New("period outside valid range 1..4e9ns")
) )
const ( const (
@@ -52,21 +50,8 @@ func getPWMGroup(index uintptr) *pwmGroup {
return (*pwmGroup)(unsafe.Pointer(uintptr(unsafe.Pointer(rp.PWM)) + 0x14*index)) return (*pwmGroup)(unsafe.Pointer(uintptr(unsafe.Pointer(rp.PWM)) + 0x14*index))
} }
// Hardware Pulse Width Modulation (PWM) API
// PWM peripherals available on RP2040. Each peripheral has 2 pins available for // PWM peripherals available on RP2040. Each peripheral has 2 pins available for
// a total of 16 available PWM outputs. Some pins may not be available on some boards. // a total of 16 available PWM outputs. Some pins may not be available on some boards.
//
// The RP2040 PWM block has 8 identical slices. Each slice can drive two PWM output signals, or
// measure the frequency or duty cycle of an input signal. This gives a total of up to 16 controllable
// PWM outputs. All 30 GPIOs can be driven by the PWM block
//
// The PWM hardware functions by continuously comparing the input value to a free-running counter. This produces a
// toggling output where the amount of time spent at the high output level is proportional to the input value. The fraction of
// time spent at the high signal level is known as the duty cycle of the signal.
//
// The default behaviour of a PWM slice is to count upward until the wrap value (\ref pwm_config_set_wrap) is reached, and then
// immediately wrap to 0. PWM slices also offer a phase-correct mode, where the counter starts to count downward after
// reaching TOP, until it reaches 0 again.
var ( var (
PWM0 = getPWMGroup(0) PWM0 = getPWMGroup(0)
PWM1 = getPWMGroup(1) PWM1 = getPWMGroup(1)
@@ -109,23 +94,30 @@ func (pwm *pwmGroup) peripheral() uint8 {
return uint8((uintptr(unsafe.Pointer(pwm)) - uintptr(unsafe.Pointer(rp.PWM))) / 0x14) return uint8((uintptr(unsafe.Pointer(pwm)) - uintptr(unsafe.Pointer(rp.PWM))) / 0x14)
} }
// SetPeriod updates the period of this PWM peripheral in nanoseconds. // SetPeriod updates the period of this PWM peripheral.
// To set a particular frequency, use the following formula: // To set a particular frequency, use the following formula:
// //
// period = 1e9 / frequency // period = 1e9 / frequency
// //
// Where frequency is in hertz. If you use a period of 0, a period // If you use a period of 0, a period that works well for LEDs will be picked.
// that works well for LEDs will be picked.
// //
// SetPeriod will try not to modify TOP if possible to reach the target period. // SetPeriod will not change the prescaler, but also won't change the current
// If the period is unattainable with current TOP SetPeriod will modify TOP // value in any of the channels. This means that you may need to update the
// by the bare minimum to reach the target period. It will also enable phase // value for the particular channel.
// correct to reach periods above 130ms. //
// Note that you cannot pick any arbitrary period after the PWM peripheral has
// been configured. If you want to switch between frequencies, pick the lowest
// frequency (longest period) once when calling Configure and adjust the
// frequency here as needed.
func (p *pwmGroup) SetPeriod(period uint64) error { func (p *pwmGroup) SetPeriod(period uint64) error {
if period > 0xffff_ffff {
return ErrPeriodTooBig
}
if period == 0 { if period == 0 {
period = 1e5 period = 1e5
} }
return p.setPeriod(period) p.setPeriod(period)
return nil
} }
// Top returns the current counter top, for use in duty cycle calculation. // Top returns the current counter top, for use in duty cycle calculation.
@@ -143,14 +135,14 @@ func (p *pwmGroup) Counter() uint32 {
return (p.CTR.Get() & rp.PWM_CH0_CTR_CH0_CTR_Msk) >> rp.PWM_CH0_CTR_CH0_CTR_Pos return (p.CTR.Get() & rp.PWM_CH0_CTR_CH0_CTR_Msk) >> rp.PWM_CH0_CTR_CH0_CTR_Pos
} }
// Period returns the used PWM period in nanoseconds. // Period returns the used PWM period in nanoseconds. It might deviate slightly
// from the configured period due to rounding.
func (p *pwmGroup) Period() uint64 { func (p *pwmGroup) Period() uint64 {
periodPerCycle := cpuPeriod() periodPerCycle := getPeriod()
top := p.getWrap() top := p.getWrap()
phc := p.getPhaseCorrect() phc := p.getPhaseCorrect()
Int, frac := p.getClockDiv() Int, frac := p.getClockDiv()
// Line below can overflow if operations done without care. return uint64((Int + frac/16) * (top + 1) * (phc + 1) * periodPerCycle) // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16)
return (16*uint64(Int) + uint64(frac)) * uint64((top+1)*(phc+1)*periodPerCycle) / 16 // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16)
} }
// SetInverting sets whether to invert the output of this channel. // SetInverting sets whether to invert the output of this channel.
@@ -188,12 +180,6 @@ func (p *pwmGroup) SetTop(top uint32) {
p.setWrap(uint16(top)) p.setWrap(uint16(top))
} }
// SetCounter sets counter control register. Max value is 16bit (0xffff).
// Useful for synchronising two different PWM peripherals.
func (p *pwmGroup) SetCounter(ctr uint32) {
p.CTR.Set(ctr)
}
// Enable enables or disables PWM peripheral channels. // Enable enables or disables PWM peripheral channels.
func (p *pwmGroup) Enable(enable bool) { func (p *pwmGroup) Enable(enable bool) {
p.enable(enable) p.enable(enable)
@@ -204,6 +190,29 @@ func (p *pwmGroup) IsEnabled() (enabled bool) {
return (p.CSR.Get()&rp.PWM_CH0_CSR_EN_Msk)>>rp.PWM_CH0_CSR_EN_Pos != 0 return (p.CSR.Get()&rp.PWM_CH0_CSR_EN_Msk)>>rp.PWM_CH0_CSR_EN_Pos != 0
} }
// Hardware Pulse Width Modulation (PWM) API
//
// The RP2040 PWM block has 8 identical slices. Each slice can drive two PWM output signals, or
// measure the frequency or duty cycle of an input signal. This gives a total of up to 16 controllable
// PWM outputs. All 30 GPIOs can be driven by the PWM block
//
// The PWM hardware functions by continuously comparing the input value to a free-running counter. This produces a
// toggling output where the amount of time spent at the high output level is proportional to the input value. The fraction of
// time spent at the high signal level is known as the duty cycle of the signal.
//
// The default behaviour of a PWM slice is to count upward until the wrap value (\ref pwm_config_set_wrap) is reached, and then
// immediately wrap to 0. PWM slices also offer a phase-correct mode, where the counter starts to count downward after
// reaching TOP, until it reaches 0 again.
type pwms struct {
slice pwmGroup
hw *rp.PWM_Type
}
// Handle to all pwm peripheral registers.
var _PWM = pwms{
hw: rp.PWM,
}
// Initialise a PWM with settings from a configuration object. // Initialise a PWM with settings from a configuration object.
// If start is true then PWM starts on initialization. // If start is true then PWM starts on initialization.
func (pwm *pwmGroup) init(config PWMConfig, start bool) error { func (pwm *pwmGroup) init(config PWMConfig, start bool) error {
@@ -244,53 +253,24 @@ func (pwm *pwmGroup) setDivMode(mode uint32) {
pwm.CSR.ReplaceBits(mode<<rp.PWM_CH0_CSR_DIVMODE_Pos, rp.PWM_CH0_CSR_DIVMODE_Msk, 0) pwm.CSR.ReplaceBits(mode<<rp.PWM_CH0_CSR_DIVMODE_Pos, rp.PWM_CH0_CSR_DIVMODE_Msk, 0)
} }
// setPeriod sets the pwm peripheral period (frequency). Calculates DIV_INT,DIV_FRAC and sets it from following equation: // setPeriod sets the pwm peripheral period (frequency). Calculates DIV_INT and sets it from following equation:
// cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16) // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16)
// where cycles is amount of clock cycles per PWM period. // where cycles is amount of clock cycles per PWM period.
func (pwm *pwmGroup) setPeriod(period uint64) error { func (pwm *pwmGroup) setPeriod(period uint64) {
// This period calculation algorithm consists of targetPeriod := uint32(period)
// 1. Calculating best-fit prescale at a slightly lower-than-max TOP value periodPerCycle := getPeriod()
// 2. Calculate TOP value to reach target period given the calculated prescale top := pwm.getWrap()
// 3. Apply calculated Prescale from step 1 and calculated Top from step 2 phc := pwm.getPhaseCorrect()
const ( _, frac := pwm.getClockDiv()
maxTop = math.MaxUint16
// start algorithm at 95% Top. This allows us to undershoot period with prescale.
topStart = 95 * maxTop / 100
milliseconds = 1_000_000_000
// Maximum Period is 268369920ns on rp2040, given by (16*255+15)*8*(1+0xffff)*(1+1)/16
// With no phase shift max period is half of this value.
maxPeriod = 268 * milliseconds
)
if period > maxPeriod || period < 8 {
return ErrBadPeriod
}
if period > maxPeriod/2 {
pwm.setPhaseCorrect(true) // Must enable Phase correct to reach large periods.
}
// clearing above expression: // clearing above expression:
// DIV_INT + DIV_FRAC/16 = cycles / ( (TOP+1) * (CSRPHCorrect+1) ) // DIV_FRAC/16 is always 0 in this equation // DIV_INT = cycles / ( (TOP+1) * (CSRPHCorrect+1) ) - DIV_FRAC/16
// where cycles must be converted to time: // where cycles must be converted to time:
// target_period = cycles * period_per_cycle ==> cycles = target_period/period_per_cycle // target_period = cycles * period_per_cycle ==> cycles = target_period/period_per_cycle
periodPerCycle := uint64(cpuPeriod()) Int := targetPeriod/((1+phc)*periodPerCycle*(1+top)) - frac/16
phc := uint64(pwm.getPhaseCorrect()) if Int > 0xff {
rhs := 16 * period / ((1 + phc) * periodPerCycle * (1 + topStart)) // right-hand-side of equation, scaled so frac is not divided Int = 0xff
whole := rhs / 16
frac := rhs % 16
if whole > 0xff {
whole = 0xff
} }
pwm.setClockDiv(uint8(Int), 0)
// Step 2 is acquiring a better top value. Clearing the equation:
// TOP = cycles / ( (DIVINT+DIVFRAC/16) * (CSRPHCorrect+1) ) - 1
top := 16*period/((16*whole+frac)*periodPerCycle*(1+phc)) - 1
if top > maxTop {
top = maxTop
}
pwm.SetTop(uint32(top))
pwm.setClockDiv(uint8(whole), uint8(frac))
return nil
} }
// Int is integer value to reduce counting rate by. Must be greater than or equal to 1. DIV_INT is bits 4:11 (8 bits). // Int is integer value to reduce counting rate by. Must be greater than or equal to 1. DIV_INT is bits 4:11 (8 bits).
@@ -380,9 +360,9 @@ func (pwm *pwmGroup) getPhaseCorrect() (phCorrect uint32) {
return (pwm.CSR.Get() & rp.PWM_CH0_CSR_PH_CORRECT_Msk) >> rp.PWM_CH0_CSR_PH_CORRECT_Pos return (pwm.CSR.Get() & rp.PWM_CH0_CSR_PH_CORRECT_Msk) >> rp.PWM_CH0_CSR_PH_CORRECT_Pos
} }
func (pwm *pwmGroup) getClockDiv() (Int, frac uint8) { func (pwm *pwmGroup) getClockDiv() (Int, frac uint32) {
div := pwm.DIV.Get() div := pwm.DIV.Get()
return uint8((div & rp.PWM_CH0_DIV_INT_Msk) >> rp.PWM_CH0_DIV_INT_Pos), uint8((div & rp.PWM_CH0_DIV_FRAC_Msk) >> rp.PWM_CH0_DIV_FRAC_Pos) return (div & rp.PWM_CH0_DIV_INT_Msk) >> rp.PWM_CH0_DIV_INT_Pos, (div & rp.PWM_CH0_DIV_FRAC_Msk) >> rp.PWM_CH0_DIV_FRAC_Pos
} }
// pwmGPIOToSlice Determine the PWM channel that is attached to the specified GPIO. // pwmGPIOToSlice Determine the PWM channel that is attached to the specified GPIO.
@@ -396,3 +376,9 @@ func pwmGPIOToSlice(gpio Pin) (slicenum uint8) {
func pwmGPIOToChannel(gpio Pin) (channel uint8) { func pwmGPIOToChannel(gpio Pin) (channel uint8) {
return uint8(gpio) & 1 return uint8(gpio) & 1
} }
// Returns the period of a clock cycle for the raspberry pi pico in nanoseconds.
func getPeriod() uint32 {
const periodIn uint32 = 1e9 / (125 * MHz)
return periodIn
}
-15
View File
@@ -1,17 +1,2 @@
// Package debug is a dummy package that is not yet implemented. // Package debug is a dummy package that is not yet implemented.
package debug package debug
// SetMaxStack sets the maximum amount of memory that can be used by a single
// goroutine stack.
//
// Not implemented.
func SetMaxStack(n int) int {
return n
}
// Stack returns a formatted stack trace of the goroutine that calls it.
//
// Not implemented.
func Stack() []byte {
return nil
}
+28
View File
@@ -29,6 +29,34 @@ func setEventHandler(fn func()) {
handleEvent = fn handleEvent = fn
} }
//export resume
func resume() {
go func() {
handleEvent()
}()
if wasmNested {
minSched()
return
}
wasmNested = true
scheduler()
wasmNested = false
}
//export go_scheduler
func go_scheduler() {
if wasmNested {
minSched()
return
}
wasmNested = true
scheduler()
wasmNested = false
}
func ticksToNanoseconds(ticks timeUnit) int64 { func ticksToNanoseconds(ticks timeUnit) int64 {
// The JavaScript API works in float64 milliseconds, so convert to // The JavaScript API works in float64 milliseconds, so convert to
// nanoseconds first before converting to a timeUnit (which is a float64), // nanoseconds first before converting to a timeUnit (which is a float64),
-32
View File
@@ -1,32 +0,0 @@
//go:build wasm && !wasi && !scheduler.none
// +build wasm,!wasi,!scheduler.none
package runtime
//export resume
func resume() {
go func() {
handleEvent()
}()
if wasmNested {
minSched()
return
}
wasmNested = true
scheduler()
wasmNested = false
}
//export go_scheduler
func go_scheduler() {
if wasmNested {
minSched()
return
}
wasmNested = true
scheduler()
wasmNested = false
}
-18
View File
@@ -297,24 +297,6 @@ func Short() bool {
return flagShort return flagShort
} }
// Verbose reports whether the -test.v flag is set.
func Verbose() bool {
return flagVerbose
}
// AllocsPerRun returns the average number of allocations during calls to f.
// Although the return value has type float64, it will always be an integral
// value.
//
// Not implemented.
func AllocsPerRun(runs int, f func()) (avg float64) {
f()
for i := 0; i < runs; i++ {
f()
}
return 0
}
func TestMain(m *M) { func TestMain(m *M) {
os.Exit(m.Run()) os.Exit(m.Run())
} }
-7
View File
@@ -24,13 +24,6 @@ func main() {
println("ab" < "aa") println("ab" < "aa")
println("aa" < "ab") println("aa" < "ab")
h := "hello"
println("h < h", h < h)
println("h <= h", h <= h)
println("h == h", h == h)
println("h >= h", h >= h)
println("h > h", h > h)
println("array equality") println("array equality")
println(a1 == [2]int{1, 2}) println(a1 == [2]int{1, 2})
println(a1 != [2]int{1, 2}) println(a1 != [2]int{1, 2})
-5
View File
@@ -20,11 +20,6 @@ true
false false
false false
true true
h < h false
h <= h true
h == h true
h >= h true
h > h false
array equality array equality
true true
false false