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: |
sudo apt-get update
sudo apt-get install --no-install-recommends \
libgnutls30 libssl1.0.2 \
qemu-system-arm \
qemu-system-riscv32 \
qemu-user \
gcc-avr \
avr-libc \
ninja-build \
python3
- install-node
- install-chrome
- install-wasmtime
- install-cmake
- hack-ninja-jobs
- install-xtensa-toolchain:
variant: "linux-amd64"
- restore_cache:
keys:
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
@@ -198,7 +201,12 @@ commands:
key: llvm-build-11-linux-v4-assert
paths:
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
- run:
name: "Test TinyGo"
@@ -209,63 +217,73 @@ commands:
# necessary to keep memory consumption down and avoid OOM (for a
# 2CPU/4GB executor).
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:
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths:
- ~/.cache/go-build
- /go/pkg/mod
- install-xtensa-toolchain:
variant: "linux-amd64"
- run: make gen-device -j4
- run: make smoketest
- install-chrome
- run: make tinygo-test
- run: make wasmtest
build-linux:
steps:
- checkout
- submodules
- run:
name: "Install apt dependencies"
name: "Install apk dependencies"
command: |
sudo apt-get update
sudo apt-get install --no-install-recommends \
libgnutls30 libssl1.0.2 \
ninja-build \
python3
- install-cmake
- hack-ninja-jobs
apk add git openssh make g++ gcompat
- checkout
- run:
name: "Install Go"
command: |
wget https://dl.google.com/go/go1.17.3.linux-amd64.tar.gz
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:
name: "Restore Go cache"
keys:
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-v2-{{ checksum "go.mod" }}
- llvm-source-linux
- go-cache-alpine-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-alpine-v2-{{ checksum "go.mod" }}
- restore_cache:
name: "Restore llvm-source cache"
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:
name: "Build LLVM"
command: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# fetch LLVM source (may only have headers right now)
rm -rf llvm-project
make llvm-source
#rm -rf llvm-project
#make llvm-source
# install dependencies
apk add cmake samurai python3
# build!
make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
SAMUFLAGS=-j3 make llvm-build
#find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
fi
- save_cache:
key: llvm-build-11-linux-v4-noassert
name: "Save llvm-build cache"
key: llvm-build-11-alpine-v1-noassert-x0
paths:
llvm-build
- build-binaryen-linux-stretch
- build-wasi-libc
- run:
name: "Install fpm"
command: |
@@ -286,7 +304,8 @@ commands:
- store_artifacts:
path: /tmp/tinygo_amd64.deb
- 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:
- ~/.cache/go-build
- /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
sudo tar -C /usr/local -xzf go1.17.darwin-amd64.tar.gz
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:
variant: "macos"
- restore_cache:
@@ -388,7 +407,7 @@ commands:
- lib/wasi-libc/sysroot
- run:
name: "Test TinyGo"
command: make test GOTESTFLAGS="-v -short"
command: make test
no_output_timeout: 20m
- run:
name: "Build TinyGo release"
@@ -426,12 +445,12 @@ jobs:
llvm: "11"
assert-test-linux:
docker:
- image: circleci/golang:1.17-buster
- image: circleci/golang:1.17-stretch
steps:
- assert-test-linux
build-linux:
docker:
- image: circleci/golang:1.17-stretch
- image: alpine:3.14
steps:
- build-linux
test-linux-build:
@@ -450,11 +469,11 @@ jobs:
workflows:
test-all:
jobs:
- test-llvm11-go115
- test-llvm11-go116
#- test-llvm11-go115
#- test-llvm11-go116
- build-linux
- test-linux-build:
requires:
- build-linux
- build-macos
- assert-test-linux
#- build-macos
#- assert-test-linux
+7 -2
View File
@@ -1,7 +1,7 @@
name: Windows
on:
pull_request:
#pull_request:
push:
branches:
- dev
@@ -15,6 +15,11 @@ jobs:
uses: actions/setup-go@v2
with:
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
shell: bash
run: |
@@ -73,7 +78,7 @@ jobs:
run: make binaryen
- name: Test TinyGo
shell: bash
run: make test GOTESTFLAGS="-v -short"
run: make test
- name: Build TinyGo release tarball
run: make build/release -j4
- 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
---
+3 -6
View File
@@ -18,9 +18,6 @@ LLVM_NM ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-nm))$(call detec
GO ?= go
export GOROOT = $(shell $(GO) env GOROOT)
# Flags to pass to go test.
GOTESTFLAGS ?= -v
# md5sum binary
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)
# Build LLVM.
$(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja
cd $(LLVM_BUILDDIR) && ninja $(NINJA_BUILD_TARGETS)
$(LLVM_BUILDDIR): #$(LLVM_BUILDDIR)/build.ninja
cd $(LLVM_BUILDDIR) && ninja llvm-nm #$(NINJA_BUILD_TARGETS)
# Build 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`" .
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 = \
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: // !=
result := b.createRuntimeCall("stringEqual", []llvm.Value{x, y}, "")
return b.CreateNot(result, ""), nil
case token.LSS: // x < y
case token.LSS: // <
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}, "")
return b.CreateNot(result, ""), nil
case token.GTR: // x > y becomes y < x
return b.createRuntimeCall("stringLess", []llvm.Value{y, x}, ""), nil
case token.GEQ: // x >= y becomes NOT (x < y)
case token.GTR: // >
result := b.createRuntimeCall("stringLess", []llvm.Value{x, y}, "")
return b.CreateNot(result, ""), nil
case token.GEQ: // >=
return b.createRuntimeCall("stringLess", []llvm.Value{y, x}, ""), nil
default:
panic("binop on string: " + op.String())
}
+3 -2
View File
@@ -71,8 +71,9 @@ entry:
; 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 {
entry:
%0 = call i1 @runtime.stringLess(i8* %s2.data, i32 %s2.len, i8* %s1.data, i32 %s1.len, i8* undef, i8* null) #0
ret i1 %0
%0 = call i1 @runtime.stringLess(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null) #0
%1 = xor i1 %0, true
ret i1 %1
}
declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*, i8*)
+1 -1
View File
@@ -12,7 +12,7 @@ import (
// Version of TinyGo.
// Update this value before release of new version of software.
const Version = "0.21.0"
const Version = "0.21.0-dev"
// GetGorootVersion returns the major and minor version for a given GOROOT path.
// 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)
})
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.
t.Run("build-options", func(t *testing.T) {
t.Parallel()
@@ -116,38 +150,6 @@ func TestCompiler(t *testing.T) {
}, 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) {
@@ -164,7 +166,7 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
t.Parallel()
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.Parallel()
options := compileopts.Options(options)
-6
View File
@@ -18,12 +18,6 @@ func CPUFrequency() uint32 {
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
type clockIndex uint8
+63 -77
View File
@@ -1,4 +1,3 @@
//go:build rp2040
// +build rp2040
package machine
@@ -6,13 +5,12 @@ package machine
import (
"device/rp"
"errors"
"math"
"runtime/volatile"
"unsafe"
)
var (
ErrBadPeriod = errors.New("period outside valid range 8ns..268ms")
ErrPeriodTooBig = errors.New("period outside valid range 1..4e9ns")
)
const (
@@ -52,21 +50,8 @@ func getPWMGroup(index uintptr) *pwmGroup {
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
// 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 (
PWM0 = getPWMGroup(0)
PWM1 = getPWMGroup(1)
@@ -109,23 +94,30 @@ func (pwm *pwmGroup) peripheral() uint8 {
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:
//
// period = 1e9 / frequency
//
// Where frequency is in hertz. If you use a period of 0, a period
// that works well for LEDs will be picked.
// If you use a period of 0, a period that works well for LEDs will be picked.
//
// SetPeriod will try not to modify TOP if possible to reach the target period.
// If the period is unattainable with current TOP SetPeriod will modify TOP
// by the bare minimum to reach the target period. It will also enable phase
// correct to reach periods above 130ms.
// SetPeriod will not change the prescaler, but also won't change the current
// value in any of the channels. This means that you may need to update the
// value for the particular channel.
//
// 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 {
if period > 0xffff_ffff {
return ErrPeriodTooBig
}
if period == 0 {
period = 1e5
}
return p.setPeriod(period)
p.setPeriod(period)
return nil
}
// 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
}
// 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 {
periodPerCycle := cpuPeriod()
periodPerCycle := getPeriod()
top := p.getWrap()
phc := p.getPhaseCorrect()
Int, frac := p.getClockDiv()
// Line below can overflow if operations done without care.
return (16*uint64(Int) + uint64(frac)) * uint64((top+1)*(phc+1)*periodPerCycle) / 16 // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16)
return uint64((Int + frac/16) * (top + 1) * (phc + 1) * periodPerCycle) // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16)
}
// SetInverting sets whether to invert the output of this channel.
@@ -188,12 +180,6 @@ func (p *pwmGroup) SetTop(top uint32) {
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.
func (p *pwmGroup) Enable(enable bool) {
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
}
// 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.
// If start is true then PWM starts on initialization.
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)
}
// 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)
// where cycles is amount of clock cycles per PWM period.
func (pwm *pwmGroup) setPeriod(period uint64) error {
// This period calculation algorithm consists of
// 1. Calculating best-fit prescale at a slightly lower-than-max TOP value
// 2. Calculate TOP value to reach target period given the calculated prescale
// 3. Apply calculated Prescale from step 1 and calculated Top from step 2
const (
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.
}
func (pwm *pwmGroup) setPeriod(period uint64) {
targetPeriod := uint32(period)
periodPerCycle := getPeriod()
top := pwm.getWrap()
phc := pwm.getPhaseCorrect()
_, frac := pwm.getClockDiv()
// 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:
// target_period = cycles * period_per_cycle ==> cycles = target_period/period_per_cycle
periodPerCycle := uint64(cpuPeriod())
phc := uint64(pwm.getPhaseCorrect())
rhs := 16 * period / ((1 + phc) * periodPerCycle * (1 + topStart)) // right-hand-side of equation, scaled so frac is not divided
whole := rhs / 16
frac := rhs % 16
if whole > 0xff {
whole = 0xff
Int := targetPeriod/((1+phc)*periodPerCycle*(1+top)) - frac/16
if Int > 0xff {
Int = 0xff
}
// 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
pwm.setClockDiv(uint8(Int), 0)
}
// 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
}
func (pwm *pwmGroup) getClockDiv() (Int, frac uint8) {
func (pwm *pwmGroup) getClockDiv() (Int, frac uint32) {
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.
@@ -396,3 +376,9 @@ func pwmGPIOToSlice(gpio Pin) (slicenum uint8) {
func pwmGPIOToChannel(gpio Pin) (channel uint8) {
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
// 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
}
//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 {
// The JavaScript API works in float64 milliseconds, so convert to
// 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
}
// 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) {
os.Exit(m.Run())
}
-7
View File
@@ -24,13 +24,6 @@ func main() {
println("ab" < "aa")
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(a1 == [2]int{1, 2})
println(a1 != [2]int{1, 2})
-5
View File
@@ -20,11 +20,6 @@ true
false
false
true
h < h false
h <= h true
h == h true
h >= h true
h > h false
array equality
true
false