mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 22:58:41 +00:00
Compare commits
56 Commits
pr3119
...
machinecheck
| Author | SHA1 | Date | |
|---|---|---|---|
| df8add7b60 | |||
| fca2de21b1 | |||
| 107b1c2906 | |||
| 2409bbef69 | |||
| 8b078a9e8f | |||
| 9e24441978 | |||
| 1e6c14b3e4 | |||
| 25f6be1488 | |||
| 9a9106a297 | |||
| a68f7e4ce3 | |||
| 70b3ece6ec | |||
| 86ea216e7d | |||
| 5a92c35536 | |||
| 7513fa2c96 | |||
| bc946f346d | |||
| 6e6666519c | |||
| cecae8084c | |||
| 9720ccacbb | |||
| a5aa777c7b | |||
| aca1ad187d | |||
| 5a41ed6329 | |||
| 91e9c84d85 | |||
| 4af530f238 | |||
| d3863f337d | |||
| 5551ec7a1e | |||
| 91104b2f27 | |||
| 80f38e8449 | |||
| 22893c5180 | |||
| 9e4e182615 | |||
| 5f96d2b784 | |||
| bd1d93b705 | |||
| 03d1c44265 | |||
| dc0346d968 | |||
| dadae95448 | |||
| f5fc2fc072 | |||
| 4ba76a5df9 | |||
| ea1e08f53f | |||
| bba0dc9575 | |||
| 617c7586fe | |||
| 7366d5e185 | |||
| 96e3ecd949 | |||
| 8bbfb1ee68 | |||
| 07cdcc61f7 | |||
| 4ca9b34133 | |||
| d5e4b16911 | |||
| fd05254683 | |||
| c579e7e509 | |||
| d463528a72 | |||
| 49b0086f8f | |||
| d7814ff50b | |||
| 02160aa8d8 | |||
| c199dd03c7 | |||
| 472aecf07a | |||
| 09350e5719 | |||
| 623dd6a815 | |||
| e09bd5abb3 |
+1
-10
@@ -118,13 +118,7 @@ jobs:
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "14"
|
||||
test-llvm14-go119:
|
||||
docker:
|
||||
- image: golang:1.19beta1-buster
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "14"
|
||||
fmt-check: false
|
||||
resource_class: large
|
||||
|
||||
workflows:
|
||||
test-all:
|
||||
@@ -132,6 +126,3 @@ workflows:
|
||||
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
||||
# least the smoke tests still pass.
|
||||
- test-llvm14-go118
|
||||
# This tests a beta version of Go. It should be removed once regular
|
||||
# release builds are built using this version.
|
||||
- test-llvm14-go119
|
||||
|
||||
@@ -16,10 +16,6 @@ jobs:
|
||||
name: build-macos
|
||||
runs-on: macos-11
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.18.1'
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -35,8 +31,13 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.19'
|
||||
cache: true
|
||||
- name: Cache LLVM source
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-14-macos-v1
|
||||
@@ -50,7 +51,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache LLVM build
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-14-macos-v1
|
||||
@@ -68,7 +69,7 @@ jobs:
|
||||
make llvm-build
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Cache wasi-libc sysroot
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-v4
|
||||
@@ -104,23 +105,17 @@ jobs:
|
||||
name: homebrew-install
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.18'
|
||||
- name: Install LLVM
|
||||
shell: bash
|
||||
run: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@14
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v2
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
key: go-cache-macos-homebrew-v1-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/Library/Caches/go-build
|
||||
~/go/pkg/mod
|
||||
go-version: '1.19'
|
||||
cache: true
|
||||
- name: Build TinyGo
|
||||
run: go install
|
||||
- name: Check binary
|
||||
|
||||
+32
-52
@@ -18,14 +18,13 @@ jobs:
|
||||
# statically linked binary.
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: alpine:3.16
|
||||
image: golang:1.19-alpine
|
||||
steps:
|
||||
- name: Install apk dependencies
|
||||
# tar: needed for actions/cache@v2
|
||||
# tar: needed for actions/cache@v3
|
||||
# git+openssh: needed for checkout (I think?)
|
||||
# gcompat: needed for go binary
|
||||
# ruby: needed to install fpm
|
||||
run: apk add tar git openssh gcompat make g++ ruby
|
||||
run: apk add tar git openssh make g++ ruby
|
||||
- name: Work around CVE-2022-24765
|
||||
# We're not on a multi-user machine, so this is safe.
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
@@ -33,19 +32,15 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.18.1'
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
- name: Cache LLVM source
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-14-linux-alpine-v1
|
||||
@@ -59,7 +54,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache LLVM build
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-14-linux-alpine-v1
|
||||
@@ -77,7 +72,7 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-alpine-v1
|
||||
@@ -88,7 +83,7 @@ jobs:
|
||||
apk add cmake samurai python3
|
||||
make binaryen STATIC=1
|
||||
- name: Cache wasi-libc
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-linux-alpine-v1
|
||||
@@ -121,9 +116,10 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.18.1'
|
||||
go-version: '1.19'
|
||||
cache: true
|
||||
- name: Install wasmtime
|
||||
run: |
|
||||
curl https://wasmtime.dev/install.sh -sSf | bash
|
||||
@@ -173,9 +169,10 @@ jobs:
|
||||
simavr \
|
||||
ninja-build
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.18.1'
|
||||
go-version: '1.19'
|
||||
cache: true
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
@@ -184,15 +181,8 @@ jobs:
|
||||
run: |
|
||||
curl https://wasmtime.dev/install.sh -sSf | bash
|
||||
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
key: go-cache-linux-asserts-v1-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
- name: Cache LLVM source
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-14-linux-asserts-v2
|
||||
@@ -206,7 +196,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache LLVM build
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-14-linux-asserts-v1
|
||||
@@ -222,7 +212,7 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-asserts-v1
|
||||
@@ -231,7 +221,7 @@ jobs:
|
||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
||||
run: make binaryen
|
||||
- name: Cache wasi-libc
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-linux-asserts-v5
|
||||
@@ -246,6 +236,8 @@ jobs:
|
||||
run: |
|
||||
make ASSERT=1
|
||||
echo "$(pwd)/build" >> $GITHUB_PATH
|
||||
- name: Test machine package
|
||||
run: make check-machine
|
||||
- name: Test stdlib packages
|
||||
run: make tinygo-test
|
||||
- name: Install Xtensa toolchain
|
||||
@@ -279,18 +271,12 @@ jobs:
|
||||
g++-arm-linux-gnueabihf \
|
||||
libc6-dev-armhf-cross
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.18.1'
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
key: go-cache-linux-arm-v2-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
go-version: '1.19'
|
||||
cache: true
|
||||
- name: Cache LLVM source
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-14-linux-v2
|
||||
@@ -304,7 +290,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache LLVM build
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-14-linux-arm-v1
|
||||
@@ -322,7 +308,7 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-arm-v1
|
||||
@@ -385,18 +371,12 @@ jobs:
|
||||
libc6-dev-arm64-cross \
|
||||
ninja-build
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.18.1'
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
key: go-cache-linux-arm64-v2-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
go-version: '1.19'
|
||||
cache: true
|
||||
- name: Cache LLVM source
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-14-linux-v1
|
||||
@@ -410,7 +390,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache LLVM build
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-14-linux-arm64-v1
|
||||
@@ -426,7 +406,7 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-arm64-v1
|
||||
|
||||
@@ -15,10 +15,6 @@ jobs:
|
||||
build-windows:
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.18.1'
|
||||
- uses: brechtm/setup-scoop@v2
|
||||
with:
|
||||
scoop_update: 'false'
|
||||
@@ -30,15 +26,13 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: true
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v2
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
key: go-cache-windows-v1-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/AppData/Local/go-build
|
||||
~/go/pkg/mod
|
||||
go-version: '1.19'
|
||||
cache: true
|
||||
- name: Cache LLVM source
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-14-windows-v2
|
||||
@@ -52,7 +46,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache LLVM build
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-14-windows-v2
|
||||
@@ -69,7 +63,7 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Cache wasi-libc sysroot
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-v4
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||
FROM golang:1.18 AS tinygo-llvm
|
||||
FROM golang:1.19 AS tinygo-llvm
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y apt-utils make cmake clang-11 binutils-avr gcc-avr avr-libc ninja-build
|
||||
|
||||
@@ -267,6 +267,18 @@ tinygo:
|
||||
test: wasi-libc
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||
|
||||
# Check whether the machine package matches the documentation.
|
||||
# TODO: improve `tinygo targets` so it doesn't return these invalid targets.
|
||||
CHECK_MACHINE_EXCULDE = \
|
||||
cortex-m-qemu \
|
||||
particle-3rd-gen \
|
||||
riscv-qemu \
|
||||
riscv64-qemu \
|
||||
rp2040 \
|
||||
$(nil)
|
||||
check-machine:
|
||||
$(GO) run ./tools/machinecheck $(filter-out $(CHECK_MACHINE_EXCULDE),$(shell $(TINYGO) targets))
|
||||
|
||||
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
|
||||
TEST_PACKAGES_SLOW = \
|
||||
compress/bzip2 \
|
||||
@@ -326,11 +338,14 @@ TEST_PACKAGES_FAST += crypto/elliptic/internal/fiat
|
||||
endif
|
||||
|
||||
# archive/zip requires os.ReadAt, which is not yet supported on windows
|
||||
# compress/flate appears to hang on wasi
|
||||
# compress/lzw appears to hang on wasi
|
||||
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic
|
||||
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows
|
||||
# io/fs requires os.ReadDir, which is not yet supported on windows or wasi
|
||||
# io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi
|
||||
# strconv requires recover() which is not yet supported on wasi
|
||||
# text/template/parse requires recover(), which is not yet supported on wasi
|
||||
# testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi
|
||||
# compress/flate fails windows go 1.18, https://github.com/tinygo-org/tinygo/issues/2762
|
||||
# compress/lzw fails windows go 1.18 wasi, https://github.com/tinygo-org/tinygo/issues/2762
|
||||
|
||||
# Additional standard library packages that pass tests on individual platforms
|
||||
TEST_PACKAGES_LINUX := \
|
||||
@@ -340,7 +355,6 @@ TEST_PACKAGES_LINUX := \
|
||||
crypto/hmac \
|
||||
debug/dwarf \
|
||||
debug/plan9obj \
|
||||
io/fs \
|
||||
io/ioutil \
|
||||
strconv \
|
||||
testing/fstest \
|
||||
@@ -349,7 +363,12 @@ TEST_PACKAGES_LINUX := \
|
||||
TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
|
||||
|
||||
TEST_PACKAGES_WINDOWS := \
|
||||
compress/lzw
|
||||
compress/flate \
|
||||
compress/lzw \
|
||||
crypto/hmac \
|
||||
strconv \
|
||||
text/template/parse \
|
||||
$(nil)
|
||||
|
||||
# Report platforms on which each standard library package is known to pass tests
|
||||
jointmp := $(shell echo /tmp/join.$$$$)
|
||||
@@ -364,12 +383,15 @@ report-stdlib-tests-pass:
|
||||
# Standard library packages that pass tests quickly on the current platform
|
||||
ifeq ($(shell uname),Darwin)
|
||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_DARWIN)
|
||||
TEST_IOFS := true
|
||||
endif
|
||||
ifeq ($(shell uname),Linux)
|
||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_LINUX)
|
||||
TEST_IOFS := true
|
||||
endif
|
||||
ifeq ($(OS),Windows_NT)
|
||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
|
||||
TEST_IOFS := false
|
||||
endif
|
||||
|
||||
# Test known-working standard library packages.
|
||||
@@ -377,6 +399,12 @@ endif
|
||||
.PHONY: tinygo-test
|
||||
tinygo-test:
|
||||
$(TINYGO) test $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
|
||||
@# io/fs requires os.ReadDir, not yet supported on windows or wasi. It also
|
||||
@# requires a large stack-size. Hence, io/fs is only run conditionally.
|
||||
@# For more details, see the comments on issue #3143.
|
||||
ifeq ($(TEST_IOFS),true)
|
||||
$(TINYGO) test -stack-size=6MB io/fs
|
||||
endif
|
||||
tinygo-test-fast:
|
||||
$(TINYGO) test $(TEST_PACKAGES_HOST)
|
||||
tinygo-bench:
|
||||
@@ -386,9 +414,9 @@ tinygo-bench-fast:
|
||||
|
||||
# Same thing, except for wasi rather than the current platform.
|
||||
tinygo-test-wasi:
|
||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
|
||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||
tinygo-test-wasi-fast:
|
||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST)
|
||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||
tinygo-bench-wasi:
|
||||
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
|
||||
tinygo-bench-wasi-fast:
|
||||
@@ -410,6 +438,7 @@ tinygo-baremetal:
|
||||
.PHONY: smoketest
|
||||
smoketest:
|
||||
$(TINYGO) version
|
||||
$(TINYGO) targets > /dev/null
|
||||
# regression test for #2892
|
||||
cd tests/testing/recurse && ($(TINYGO) test ./... > recurse.log && cat recurse.log && test $$(wc -l < recurse.log) = 2 && rm recurse.log)
|
||||
# compile-only platform-independent examples
|
||||
@@ -519,6 +548,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=matrixportal-m4 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pybadge examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=metro-m4-airlift examples/blinky1
|
||||
@@ -585,6 +616,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=qtpy-rp2040 examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=macropad-rp2040 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=badger2040 examples/blinky1
|
||||
@@ -597,7 +630,7 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=challenger-rp2040 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=trinkey-qt2040 examples/adc_rp2040
|
||||
$(TINYGO) build -size short -o test.hex -target=trinkey-qt2040 examples/temp
|
||||
@$(MD5SUM) test.hex
|
||||
# test pwm
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||
@@ -679,7 +712,9 @@ ifneq ($(XTENSA), 0)
|
||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
endif
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
@@ -687,8 +722,6 @@ endif
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=hifive1-qemu examples/serial
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
ifneq ($(WASM), 0)
|
||||
|
||||
@@ -66,6 +66,7 @@ The following 91 microcontroller boards are currently supported:
|
||||
* [Adafruit PyGamer](https://www.adafruit.com/product/4242)
|
||||
* [Adafruit PyPortal](https://www.adafruit.com/product/4116)
|
||||
* [Adafruit QT Py](https://www.adafruit.com/product/4600)
|
||||
* [Adafruit QT Py RP2040](https://www.adafruit.com/product/4900)
|
||||
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
|
||||
* [Adafruit Trinkey QT2040](https://adafruit.com/product/5056)
|
||||
* [Arduino Mega 1280](https://www.arduino.cc/en/Main/arduinoBoardMega/)
|
||||
@@ -124,7 +125,7 @@ The following 91 microcontroller boards are currently supported:
|
||||
* [Seeed LoRa-E5 Development Kit](https://www.seeedstudio.com/LoRa-E5-Dev-Kit-p-4868.html)
|
||||
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
|
||||
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
|
||||
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1)
|
||||
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1-rev-b)
|
||||
* [Sparkfun Thing Plus RP2040](https://www.sparkfun.com/products/17745)
|
||||
* [ST Micro "Nucleo" F103RB](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html)
|
||||
* [ST Micro "Nucleo" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
|
||||
Scheduler: config.Scheduler(),
|
||||
AutomaticStackSize: config.AutomaticStackSize(),
|
||||
DefaultStackSize: config.Target.DefaultStackSize,
|
||||
DefaultStackSize: config.StackSize(),
|
||||
NeedsStackObjects: config.NeedsStackObjects(),
|
||||
Debug: true,
|
||||
}
|
||||
|
||||
+57
-16
@@ -32,6 +32,7 @@ type cgoPackage struct {
|
||||
errors []error
|
||||
currentDir string // current working directory
|
||||
packageDir string // full path to the package to process
|
||||
importPath string
|
||||
fset *token.FileSet
|
||||
tokenFiles map[string]*token.File
|
||||
definedGlobally map[string]ast.Node
|
||||
@@ -39,12 +40,15 @@ type cgoPackage struct {
|
||||
cflags []string // CFlags from #cgo lines
|
||||
ldflags []string // LDFlags from #cgo lines
|
||||
visitedFiles map[string][]byte
|
||||
cgoHeaders []string
|
||||
}
|
||||
|
||||
// cgoFile holds information only for a single Go file (with one or more
|
||||
// `import "C"` statements).
|
||||
type cgoFile struct {
|
||||
*cgoPackage
|
||||
file *ast.File
|
||||
index int
|
||||
defined map[string]ast.Node
|
||||
names map[string]clangCursor
|
||||
}
|
||||
@@ -158,9 +162,10 @@ func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
// functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
|
||||
// hashes of the accessed C header files. If there is one or more error, it
|
||||
// returns these in the []error slice but still modifies the AST.
|
||||
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string, clangHeaders string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
||||
func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cflags []string, clangHeaders string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
||||
p := &cgoPackage{
|
||||
currentDir: dir,
|
||||
importPath: importPath,
|
||||
fset: fset,
|
||||
tokenFiles: map[string]*token.File{},
|
||||
definedGlobally: map[string]ast.Node{},
|
||||
@@ -210,13 +215,13 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||
}
|
||||
}
|
||||
// Patch some types, for example *C.char in C.CString.
|
||||
cf := p.newCGoFile()
|
||||
cf := p.newCGoFile(nil, -1) // dummy *cgoFile for the walker
|
||||
astutil.Apply(p.generated, func(cursor *astutil.Cursor) bool {
|
||||
return cf.walker(cursor, nil)
|
||||
}, nil)
|
||||
|
||||
// Find `import "C"` C fragments in the file.
|
||||
cgoHeaders := make([]string, len(files)) // combined CGo header fragment for each file
|
||||
p.cgoHeaders = make([]string, len(files)) // combined CGo header fragment for each file
|
||||
for i, f := range files {
|
||||
var cgoHeader string
|
||||
for i := 0; i < len(f.Decls); i++ {
|
||||
@@ -275,7 +280,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||
cgoHeader += fragment
|
||||
}
|
||||
|
||||
cgoHeaders[i] = cgoHeader
|
||||
p.cgoHeaders[i] = cgoHeader
|
||||
}
|
||||
|
||||
// Define CFlags that will be used while parsing the package.
|
||||
@@ -289,7 +294,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||
}
|
||||
|
||||
// Retrieve types such as C.int, C.longlong, etc from C.
|
||||
p.newCGoFile().readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) {
|
||||
p.newCGoFile(nil, -1).readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) {
|
||||
gen := &ast.GenDecl{
|
||||
TokPos: token.NoPos,
|
||||
Tok: token.TYPE,
|
||||
@@ -303,8 +308,8 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||
|
||||
// Process CGo imports for each file.
|
||||
for i, f := range files {
|
||||
cf := p.newCGoFile()
|
||||
cf.readNames(cgoHeaders[i], cflagsForCGo, filepath.Base(fset.File(f.Pos()).Name()), func(names map[string]clangCursor) {
|
||||
cf := p.newCGoFile(f, i)
|
||||
cf.readNames(p.cgoHeaders[i], cflagsForCGo, filepath.Base(fset.File(f.Pos()).Name()), func(names map[string]clangCursor) {
|
||||
for _, name := range builtinAliases {
|
||||
// Names such as C.int should not be obtained from C.
|
||||
// This works around an issue in picolibc that has `#define int`
|
||||
@@ -320,12 +325,14 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||
// Print the newly generated in-memory AST, for debugging.
|
||||
//ast.Print(fset, p.generated)
|
||||
|
||||
return p.generated, cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
|
||||
return p.generated, p.cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
|
||||
}
|
||||
|
||||
func (p *cgoPackage) newCGoFile() *cgoFile {
|
||||
func (p *cgoPackage) newCGoFile(file *ast.File, index int) *cgoFile {
|
||||
return &cgoFile{
|
||||
cgoPackage: p,
|
||||
file: file,
|
||||
index: index,
|
||||
defined: make(map[string]ast.Node),
|
||||
names: make(map[string]clangCursor),
|
||||
}
|
||||
@@ -1117,8 +1124,11 @@ func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) st
|
||||
return alias
|
||||
}
|
||||
node := f.getASTDeclNode(name, found, iscall)
|
||||
if _, ok := node.(*ast.FuncDecl); ok && !iscall {
|
||||
return "C." + name + "$funcaddr"
|
||||
if node, ok := node.(*ast.FuncDecl); ok {
|
||||
if !iscall {
|
||||
return node.Name.Name + "$funcaddr"
|
||||
}
|
||||
return node.Name.Name
|
||||
}
|
||||
return "C." + name
|
||||
}
|
||||
@@ -1142,7 +1152,7 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
|
||||
// Original cgo reports an error like
|
||||
// cgo: inconsistent definitions for C.myint
|
||||
// which is far less helpful.
|
||||
f.addError(getPos(node), "defined previously at "+f.fset.Position(getPos(newNode)).String()+" with a different type")
|
||||
f.addError(getPos(node), name+" defined previously at "+f.fset.Position(getPos(newNode)).String()+" with a different type")
|
||||
}
|
||||
f.defined[name] = node
|
||||
return node
|
||||
@@ -1150,11 +1160,39 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
|
||||
|
||||
// The declaration has no AST node. Create it now.
|
||||
f.defined[name] = nil
|
||||
node, elaboratedType := f.createASTNode(name, found)
|
||||
node, extra := f.createASTNode(name, found)
|
||||
f.defined[name] = node
|
||||
f.definedGlobally[name] = node
|
||||
switch node := node.(type) {
|
||||
case *ast.FuncDecl:
|
||||
if strings.HasPrefix(node.Doc.List[0].Text, "//export _Cgo_static_") {
|
||||
// Static function. Only accessible in the current Go file.
|
||||
globalName := strings.TrimPrefix(node.Doc.List[0].Text, "//export ")
|
||||
// Make an alias. Normally this is done using the alias function
|
||||
// attribute, but MacOS for some reason doesn't support this (even
|
||||
// though the linker has support for aliases in the form of N_INDR).
|
||||
// Therefore, create an actual function for MacOS.
|
||||
var params []string
|
||||
for _, param := range node.Type.Params.List {
|
||||
params = append(params, param.Names[0].Name)
|
||||
}
|
||||
callInst := fmt.Sprintf("%s(%s);", name, strings.Join(params, ", "))
|
||||
if node.Type.Results != nil {
|
||||
callInst = "return " + callInst
|
||||
}
|
||||
aliasDeclaration := fmt.Sprintf(`
|
||||
#ifdef __APPLE__
|
||||
%s {
|
||||
%s
|
||||
}
|
||||
#else
|
||||
extern __typeof(%s) %s __attribute__((alias(%#v)));
|
||||
#endif
|
||||
`, extra.(string), callInst, name, globalName, name)
|
||||
f.cgoHeaders[f.index] += "\n\n" + aliasDeclaration
|
||||
} else {
|
||||
// Regular (non-static) function.
|
||||
f.definedGlobally[name] = node
|
||||
}
|
||||
f.generated.Decls = append(f.generated.Decls, node)
|
||||
// Also add a declaration like the following:
|
||||
// var C.foo$funcaddr unsafe.Pointer
|
||||
@@ -1162,7 +1200,7 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
|
||||
Tok: token.VAR,
|
||||
Specs: []ast.Spec{
|
||||
&ast.ValueSpec{
|
||||
Names: []*ast.Ident{{Name: "C." + name + "$funcaddr"}},
|
||||
Names: []*ast.Ident{{Name: node.Name.Name + "$funcaddr"}},
|
||||
Type: &ast.SelectorExpr{
|
||||
X: &ast.Ident{Name: "unsafe"},
|
||||
Sel: &ast.Ident{Name: "Pointer"},
|
||||
@@ -1171,8 +1209,10 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
|
||||
},
|
||||
})
|
||||
case *ast.GenDecl:
|
||||
f.definedGlobally[name] = node
|
||||
f.generated.Decls = append(f.generated.Decls, node)
|
||||
case *ast.TypeSpec:
|
||||
f.definedGlobally[name] = node
|
||||
f.generated.Decls = append(f.generated.Decls, &ast.GenDecl{
|
||||
Tok: token.TYPE,
|
||||
Specs: []ast.Spec{node},
|
||||
@@ -1186,7 +1226,8 @@ func (f *cgoFile) getASTDeclNode(name string, found clangCursor, iscall bool) as
|
||||
|
||||
// If this is a struct or union it may need bitfields or union accessor
|
||||
// methods.
|
||||
if elaboratedType != nil {
|
||||
switch elaboratedType := extra.(type) {
|
||||
case *elaboratedTypeInfo:
|
||||
// Add struct bitfields.
|
||||
for _, bitfield := range elaboratedType.bitfields {
|
||||
f.createBitfieldGetter(bitfield, "C."+name)
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ func TestCGo(t *testing.T) {
|
||||
}
|
||||
|
||||
// Process the AST with CGo.
|
||||
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags, "")
|
||||
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags, "")
|
||||
|
||||
// Check the AST for type errors.
|
||||
var typecheckErrors []error
|
||||
|
||||
+33
-4
@@ -4,7 +4,9 @@ package cgo
|
||||
// modification. It does not touch the AST itself.
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/scanner"
|
||||
@@ -43,6 +45,8 @@ typedef struct {
|
||||
GoCXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu);
|
||||
unsigned tinygo_clang_visitChildren(GoCXCursor parent, CXCursorVisitor visitor, CXClientData client_data);
|
||||
CXString tinygo_clang_getCursorSpelling(GoCXCursor c);
|
||||
CXString tinygo_clang_getCursorPrettyPrinted(GoCXCursor c, CXPrintingPolicy Policy);
|
||||
CXPrintingPolicy tinygo_clang_getCursorPrintingPolicy(GoCXCursor c);
|
||||
enum CXCursorKind tinygo_clang_getCursorKind(GoCXCursor c);
|
||||
CXType tinygo_clang_getCursorType(GoCXCursor c);
|
||||
GoCXCursor tinygo_clang_getTypeDeclaration(CXType t);
|
||||
@@ -50,6 +54,7 @@ CXType tinygo_clang_getTypedefDeclUnderlyingType(GoCXCursor c);
|
||||
CXType tinygo_clang_getCursorResultType(GoCXCursor c);
|
||||
int tinygo_clang_Cursor_getNumArguments(GoCXCursor c);
|
||||
GoCXCursor tinygo_clang_Cursor_getArgument(GoCXCursor c, unsigned i);
|
||||
enum CX_StorageClass tinygo_clang_Cursor_getStorageClass(GoCXCursor c);
|
||||
CXSourceLocation tinygo_clang_getCursorLocation(GoCXCursor c);
|
||||
CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
|
||||
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
|
||||
@@ -189,7 +194,7 @@ func (f *cgoFile) readNames(fragment string, cflags []string, filename string, c
|
||||
|
||||
// Convert the AST node under the given Clang cursor to a Go AST node and return
|
||||
// it.
|
||||
func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, *elaboratedTypeInfo) {
|
||||
func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
kind := C.tinygo_clang_getCursorKind(c)
|
||||
pos := f.getCursorPosition(c)
|
||||
switch kind {
|
||||
@@ -200,19 +205,43 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, *elaborat
|
||||
Kind: ast.Fun,
|
||||
Name: "C." + name,
|
||||
}
|
||||
exportName := name
|
||||
localName := name
|
||||
var stringSignature string
|
||||
if C.tinygo_clang_Cursor_getStorageClass(c) == C.CX_SC_Static {
|
||||
// A static function is assigned a globally unique symbol name based
|
||||
// on the file path (like _Cgo_static_2d09198adbf58f4f4655_foo) and
|
||||
// has a different Go name in the form of C.foo!symbols.go instead
|
||||
// of just C.foo.
|
||||
path := f.importPath + "/" + filepath.Base(f.fset.File(f.file.Pos()).Name())
|
||||
staticIDBuf := sha256.Sum256([]byte(path))
|
||||
staticID := hex.EncodeToString(staticIDBuf[:10])
|
||||
exportName = "_Cgo_static_" + staticID + "_" + name
|
||||
localName = name + "!" + filepath.Base(path)
|
||||
|
||||
// Create a signature. This is necessary for MacOS to forward the
|
||||
// call, because MacOS doesn't support aliases like ELF and PE do.
|
||||
// (There is N_INDR but __attribute__((alias("..."))) doesn't work).
|
||||
policy := C.tinygo_clang_getCursorPrintingPolicy(c)
|
||||
defer C.clang_PrintingPolicy_dispose(policy)
|
||||
C.clang_PrintingPolicy_setProperty(policy, C.CXPrintingPolicy_TerseOutput, 1)
|
||||
stringSignature = getString(C.tinygo_clang_getCursorPrettyPrinted(c, policy))
|
||||
stringSignature = strings.Replace(stringSignature, " "+name+"(", " "+exportName+"(", 1)
|
||||
stringSignature = strings.TrimPrefix(stringSignature, "static ")
|
||||
}
|
||||
args := make([]*ast.Field, numArgs)
|
||||
decl := &ast.FuncDecl{
|
||||
Doc: &ast.CommentGroup{
|
||||
List: []*ast.Comment{
|
||||
{
|
||||
Slash: pos - 1,
|
||||
Text: "//export " + name,
|
||||
Text: "//export " + exportName,
|
||||
},
|
||||
},
|
||||
},
|
||||
Name: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: "C." + name,
|
||||
Name: "C." + localName,
|
||||
Obj: obj,
|
||||
},
|
||||
Type: &ast.FuncType{
|
||||
@@ -263,7 +292,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, *elaborat
|
||||
}
|
||||
}
|
||||
obj.Decl = decl
|
||||
return decl, nil
|
||||
return decl, stringSignature
|
||||
case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
|
||||
typ := f.makeASTRecordType(c, pos)
|
||||
typeName := "C." + name
|
||||
|
||||
@@ -17,6 +17,14 @@ CXString tinygo_clang_getCursorSpelling(CXCursor c) {
|
||||
return clang_getCursorSpelling(c);
|
||||
}
|
||||
|
||||
CXString tinygo_clang_getCursorPrettyPrinted(CXCursor c, CXPrintingPolicy policy) {
|
||||
return clang_getCursorPrettyPrinted(c, policy);
|
||||
}
|
||||
|
||||
CXPrintingPolicy tinygo_clang_getCursorPrintingPolicy(CXCursor c) {
|
||||
return clang_getCursorPrintingPolicy(c);
|
||||
}
|
||||
|
||||
enum CXCursorKind tinygo_clang_getCursorKind(CXCursor c) {
|
||||
return clang_getCursorKind(c);
|
||||
}
|
||||
@@ -45,6 +53,10 @@ CXCursor tinygo_clang_Cursor_getArgument(CXCursor c, unsigned i) {
|
||||
return clang_Cursor_getArgument(c, i);
|
||||
}
|
||||
|
||||
enum CX_StorageClass tinygo_clang_Cursor_getStorageClass(CXCursor c) {
|
||||
return clang_Cursor_getStorageClass(c);
|
||||
}
|
||||
|
||||
CXSourceLocation tinygo_clang_getCursorLocation(CXCursor c) {
|
||||
return clang_getCursorLocation(c);
|
||||
}
|
||||
|
||||
Vendored
+2
@@ -5,6 +5,7 @@ package main
|
||||
int foo(int a, int b);
|
||||
void variadic0();
|
||||
void variadic2(int x, int y, ...);
|
||||
static void staticfunc(int x);
|
||||
|
||||
// Global variable signatures.
|
||||
extern int someValue;
|
||||
@@ -16,6 +17,7 @@ func accessFunctions() {
|
||||
C.foo(3, 4)
|
||||
C.variadic0()
|
||||
C.variadic2(3, 5)
|
||||
C.staticfunc(3)
|
||||
}
|
||||
|
||||
func accessGlobals() {
|
||||
|
||||
Vendored
+5
@@ -55,5 +55,10 @@ func C.variadic2(x C.int, y C.int)
|
||||
|
||||
var C.variadic2$funcaddr unsafe.Pointer
|
||||
|
||||
//export _Cgo_static_173c95a79b6df1980521_staticfunc
|
||||
func C.staticfunc!symbols.go(x C.int)
|
||||
|
||||
var C.staticfunc!symbols.go$funcaddr unsafe.Pointer
|
||||
|
||||
//go:extern someValue
|
||||
var C.someValue C.int
|
||||
|
||||
+17
-1
@@ -175,6 +175,15 @@ func (c *Config) AutomaticStackSize() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// StackSize returns the default stack size to be used for goroutines, if the
|
||||
// stack size could not be determined automatically at compile time.
|
||||
func (c *Config) StackSize() uint64 {
|
||||
if c.Options.StackSize != 0 {
|
||||
return c.Options.StackSize
|
||||
}
|
||||
return c.Target.DefaultStackSize
|
||||
}
|
||||
|
||||
// UseThinLTO returns whether ThinLTO should be used for the given target. Some
|
||||
// targets (such as wasm) are not yet supported.
|
||||
// We should try and remove as many exceptions as possible in the future, so
|
||||
@@ -457,7 +466,14 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
|
||||
args = append(args, "-c", cmd)
|
||||
}
|
||||
if c.Target.OpenOCDTransport != "" {
|
||||
args = append(args, "-c", "transport select "+c.Target.OpenOCDTransport)
|
||||
transport := c.Target.OpenOCDTransport
|
||||
if transport == "swd" {
|
||||
switch openocdInterface {
|
||||
case "stlink-dap":
|
||||
transport = "dapdirect_swd"
|
||||
}
|
||||
}
|
||||
args = append(args, "-c", "transport select "+transport)
|
||||
}
|
||||
args = append(args, "-f", "target/"+c.Target.OpenOCDTarget+".cfg")
|
||||
return args, nil
|
||||
|
||||
@@ -28,6 +28,7 @@ type Options struct {
|
||||
GC string
|
||||
PanicStrategy string
|
||||
Scheduler string
|
||||
StackSize uint64 // goroutine stack size (if none could be automatically determined)
|
||||
Serial string
|
||||
Work bool // -work flag to print temporary build directory
|
||||
InterpTimeout time.Duration
|
||||
@@ -49,6 +50,8 @@ type Options struct {
|
||||
LLVMFeatures string
|
||||
Directory string
|
||||
PrintJSON bool
|
||||
Monitor bool
|
||||
BaudRate int
|
||||
}
|
||||
|
||||
// Verify performs a validation on the given options, raising an error if options are not valid.
|
||||
|
||||
+17
-10
@@ -65,7 +65,7 @@ type TargetSpec struct {
|
||||
}
|
||||
|
||||
// overrideProperties overrides all properties that are set in child into itself using reflection.
|
||||
func (spec *TargetSpec) overrideProperties(child *TargetSpec) {
|
||||
func (spec *TargetSpec) overrideProperties(child *TargetSpec) error {
|
||||
specType := reflect.TypeOf(spec).Elem()
|
||||
specValue := reflect.ValueOf(spec).Elem()
|
||||
childValue := reflect.ValueOf(child).Elem()
|
||||
@@ -95,14 +95,15 @@ func (spec *TargetSpec) overrideProperties(child *TargetSpec) {
|
||||
for j := i + 1; j < dst.Len(); j++ {
|
||||
w := dst.Index(j).String()
|
||||
if v == w {
|
||||
panic("duplicate value '" + v + "' in field : " + field.Name)
|
||||
return fmt.Errorf("duplicate value '%s' in field %s", v, field.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic("unknown field type : " + kind.String())
|
||||
return fmt.Errorf("unknown field type: %s", kind)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// load reads a target specification from the JSON in the given io.Reader. It
|
||||
@@ -117,10 +118,10 @@ func (spec *TargetSpec) load(r io.Reader) error {
|
||||
}
|
||||
|
||||
// loadFromGivenStr loads the TargetSpec from the given string that could be:
|
||||
// - targets/ directory inside the compiler sources
|
||||
// - a relative or absolute path to custom (project specific) target specification .json file;
|
||||
// the Inherits[] could contain the files from target folder (ex. stm32f4disco)
|
||||
// as well as path to custom files (ex. myAwesomeProject.json)
|
||||
// - targets/ directory inside the compiler sources
|
||||
// - a relative or absolute path to custom (project specific) target specification .json file;
|
||||
// the Inherits[] could contain the files from target folder (ex. stm32f4disco)
|
||||
// as well as path to custom files (ex. myAwesomeProject.json)
|
||||
func (spec *TargetSpec) loadFromGivenStr(str string) error {
|
||||
path := ""
|
||||
if strings.HasSuffix(str, ".json") {
|
||||
@@ -150,11 +151,17 @@ func (spec *TargetSpec) resolveInherits() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newSpec.overrideProperties(subtarget)
|
||||
err = newSpec.overrideProperties(subtarget)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// When all properties are loaded, make sure they are properly inherited.
|
||||
newSpec.overrideProperties(spec)
|
||||
err := newSpec.overrideProperties(spec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*spec = *newSpec
|
||||
|
||||
return nil
|
||||
@@ -221,7 +228,7 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
|
||||
// it includes all parents as specified in the "inherits" key.
|
||||
err = spec.resolveInherits()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, fmt.Errorf("%s : %w", options.Target, err)
|
||||
}
|
||||
|
||||
if spec.Scheduler == "asyncify" {
|
||||
|
||||
@@ -79,7 +79,7 @@ func TestCompiler(t *testing.T) {
|
||||
RelocationModel: config.RelocationModel(),
|
||||
Scheduler: config.Scheduler(),
|
||||
AutomaticStackSize: config.AutomaticStackSize(),
|
||||
DefaultStackSize: config.Target.DefaultStackSize,
|
||||
DefaultStackSize: config.StackSize(),
|
||||
NeedsStackObjects: config.NeedsStackObjects(),
|
||||
}
|
||||
machine, err := NewTargetMachine(compilerConfig)
|
||||
|
||||
+12
-10
@@ -163,18 +163,20 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
|
||||
// External/exported functions may not retain pointer values.
|
||||
// https://golang.org/cmd/cgo/#hdr-Passing_pointers
|
||||
if info.exported {
|
||||
// Set the wasm-import-module attribute if the function's module is set.
|
||||
if info.module != "" {
|
||||
|
||||
if c.archFamily() == "wasm32" {
|
||||
// We need to add the wasm-import-module and the wasm-import-name
|
||||
wasmImportModuleAttr := c.ctx.CreateStringAttribute("wasm-import-module", info.module)
|
||||
llvmFn.AddFunctionAttr(wasmImportModuleAttr)
|
||||
|
||||
// Add the Wasm Import Name, if we are a named wasm import
|
||||
if info.importName != "" {
|
||||
wasmImportNameAttr := c.ctx.CreateStringAttribute("wasm-import-name", info.importName)
|
||||
llvmFn.AddFunctionAttr(wasmImportNameAttr)
|
||||
// attributes.
|
||||
module := info.module
|
||||
if module == "" {
|
||||
module = "env"
|
||||
}
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", module))
|
||||
|
||||
name := info.importName
|
||||
if name == "" {
|
||||
name = info.linkName
|
||||
}
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", name))
|
||||
}
|
||||
nocaptureKind := llvm.AttributeKindID("nocapture")
|
||||
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
|
||||
|
||||
Vendored
+2
-2
@@ -62,7 +62,7 @@ declare void @main.undefinedFunctionNotInSection(i8*) #0
|
||||
|
||||
attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" }
|
||||
attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" }
|
||||
attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" }
|
||||
|
||||
@@ -9,8 +9,10 @@ require (
|
||||
github.com/chromedp/chromedp v0.7.6
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
|
||||
github.com/mattn/go-colorable v0.1.8
|
||||
github.com/mattn/go-tty v0.0.4
|
||||
go.bug.st/serial v1.3.5
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261
|
||||
golang.org/x/tools v0.1.11
|
||||
|
||||
@@ -12,7 +12,6 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA
|
||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
@@ -23,44 +22,47 @@ github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s=
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
|
||||
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
|
||||
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
|
||||
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
go.bug.st/serial v1.1.3 h1:YEBxJa9pKS9Wdg46B/jiaKbvvbUrjhZZZITfJHEJhaE=
|
||||
go.bug.st/serial v1.1.3/go.mod h1:8TT7u/SwwNIpJ8QaG4s+HTjFt9ReXs2cdOU7ZEk50Dk=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
go.bug.st/serial v1.3.5 h1:k50SqGZCnHZ2MiBQgzccXWG+kd/XpOs1jUljpDDKzaE=
|
||||
go.bug.st/serial v1.3.5/go.mod h1:z8CesKorE90Qr/oRSJiEuvzYRKol9r/anJZEb5kt304=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261 h1:v6hYoSR9T5oet+pMXwUWkbiVqx/63mlHjefrHmxwfeY=
|
||||
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
|
||||
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
tinygo.org/x/go-llvm v0.0.0-20220802112859-5bb0b77907a7 h1:nSLR52mUw7DPQQVA3ZJFH63zjU4ME84fKiin6mdnYWc=
|
||||
tinygo.org/x/go-llvm v0.0.0-20220802112859-5bb0b77907a7/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||
|
||||
@@ -369,6 +369,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
nBytes := uint32(operands[3].Uint())
|
||||
dstObj := mem.getWritable(dst.index())
|
||||
dstBuf := dstObj.buffer.asRawValue(r)
|
||||
if mem.get(src.index()).buffer == nil {
|
||||
// Looks like the source buffer is not defined.
|
||||
// This can happen with //extern or //go:embed.
|
||||
return nil, mem, r.errorAt(inst, errUnsupportedRuntimeInst)
|
||||
}
|
||||
srcBuf := mem.get(src.index()).buffer.asRawValue(r)
|
||||
copy(dstBuf.buf[dst.offset():dst.offset()+nBytes], srcBuf.buf[src.offset():])
|
||||
dstObj.buffer = dstBuf
|
||||
|
||||
+1
-1
@@ -440,7 +440,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
||||
var initialCFlags []string
|
||||
initialCFlags = append(initialCFlags, p.program.config.CFlags()...)
|
||||
initialCFlags = append(initialCFlags, "-I"+p.Dir)
|
||||
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.program.fset, initialCFlags, p.program.clangHeaders)
|
||||
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.ImportPath, p.program.fset, initialCFlags, p.program.clangHeaders)
|
||||
p.CFlags = append(initialCFlags, cflags...)
|
||||
p.CGoHeaders = headerCode
|
||||
for path, hash := range accessedFiles {
|
||||
|
||||
@@ -26,6 +26,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/shlex"
|
||||
"github.com/inhies/go-bytesize"
|
||||
"github.com/mattn/go-colorable"
|
||||
"github.com/tinygo-org/tinygo/builder"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
@@ -243,17 +244,36 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
// Tests are always run in the package directory.
|
||||
cmd.Dir = result.MainDir
|
||||
|
||||
// Wasmtime needs a few extra flags to work.
|
||||
// wasmtime is the default emulator used for `-target=wasi`. wasmtime
|
||||
// is a WebAssembly runtime CLI with WASI enabled by default. However,
|
||||
// only stdio are allowed by default. For example, while STDOUT routes
|
||||
// to the host, other files don't. It also does not inherit environment
|
||||
// variables from the host. Some tests read testdata files, often from
|
||||
// outside the package directory. Other tests require temporary
|
||||
// writeable directories. We allow this by adding wasmtime flags below.
|
||||
if config.EmulatorName() == "wasmtime" {
|
||||
// Add directories to the module root, but skip the current working
|
||||
// directory which is already added by buildAndRun.
|
||||
// At this point, The current working directory is at the package
|
||||
// directory. Ex. $GOROOT/src/compress/flate for compress/flate.
|
||||
// buildAndRun has already added arguments for wasmtime, that allow
|
||||
// read-access to files such as "testdata/huffman-zero.in".
|
||||
//
|
||||
// Ex. main(.wasm) --dir=. -- -test.v
|
||||
|
||||
// Below adds additional wasmtime flags in case a test reads files
|
||||
// outside its directory, like "../testdata/e.txt". This allows any
|
||||
// relative directory up to the module root, even if the test never
|
||||
// reads any files.
|
||||
//
|
||||
// Ex. --dir=.. --dir=../.. --dir=../../..
|
||||
dirs := dirsToModuleRoot(result.MainDir, result.ModuleRoot)
|
||||
var args []string
|
||||
for _, d := range dirs[1:] {
|
||||
args = append(args, "--dir="+d)
|
||||
}
|
||||
|
||||
// create a new temp directory just for this run, announce it to os.TempDir() via TMPDIR
|
||||
// Some tests create temp directories using os.MkdirTemp or via
|
||||
// t.TempDir(). Create a writeable directory and map it to the
|
||||
// default tempDir environment variable: TMPDIR.
|
||||
tmpdir, err := os.MkdirTemp("", "tinygotmp")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create temporary directory: %w", err)
|
||||
@@ -262,7 +282,8 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
// TODO: add option to not delete temp dir for debugging?
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
// Insert new argments at the front of the command line argments.
|
||||
// The below re-organizes the arguments so that the current
|
||||
// directory is added last.
|
||||
args = append(args, cmd.Args[1:]...)
|
||||
cmd.Args = append(cmd.Args[:1:1], args...)
|
||||
}
|
||||
@@ -402,7 +423,6 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
if err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
}
|
||||
return nil
|
||||
case "msd":
|
||||
switch fileExt {
|
||||
case ".uf2":
|
||||
@@ -410,13 +430,11 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
if err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
}
|
||||
return nil
|
||||
case ".hex":
|
||||
err := flashHexUsingMSD(config.Target.FlashVolume, result.Binary, config.Options)
|
||||
if err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return errors.New("mass storage device flashing currently only supports uf2 and hex")
|
||||
}
|
||||
@@ -437,7 +455,6 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
if err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
}
|
||||
return nil
|
||||
case "bmp":
|
||||
gdb, err := config.Target.LookupGDB()
|
||||
if err != nil {
|
||||
@@ -456,10 +473,13 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
if err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return fmt.Errorf("unknown flash method: %s", flashMethod)
|
||||
}
|
||||
if options.Monitor {
|
||||
return Monitor("", options)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -978,7 +998,8 @@ func getDefaultPort(portFlag string, usbInterfaces []string) (port string, err e
|
||||
preferredPortIDs = append(preferredPortIDs, [2]uint16{uint16(vid), uint16(pid)})
|
||||
}
|
||||
|
||||
var primaryPorts []string // ports picked from preferred USB VID/PID
|
||||
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
|
||||
@@ -1000,6 +1021,8 @@ func getDefaultPort(portFlag string, usbInterfaces []string) (port string, err e
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
secondaryPorts = append(secondaryPorts, p.Name)
|
||||
}
|
||||
if len(primaryPorts) == 1 {
|
||||
// There is exactly one match in the set of preferred ports. Use
|
||||
@@ -1011,18 +1034,10 @@ func getDefaultPort(portFlag string, usbInterfaces []string) (port string, err e
|
||||
// one device of the same type are connected (e.g. two Arduino
|
||||
// Unos).
|
||||
ports = primaryPorts
|
||||
}
|
||||
|
||||
if len(ports) == 0 {
|
||||
// fallback
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
ports, err = filepath.Glob("/dev/cu.usb*")
|
||||
case "linux":
|
||||
ports, err = filepath.Glob("/dev/ttyACM*")
|
||||
case "windows":
|
||||
ports, err = serial.GetPortsList()
|
||||
}
|
||||
} else {
|
||||
// No preferred ports found. Fall back to other serial ports
|
||||
// available in the system.
|
||||
ports = secondaryPorts
|
||||
}
|
||||
default:
|
||||
return "", errors.New("unable to search for a default USB device to be flashed on this OS")
|
||||
@@ -1037,7 +1052,9 @@ func getDefaultPort(portFlag string, usbInterfaces []string) (port string, err e
|
||||
}
|
||||
|
||||
if len(portCandidates) == 0 {
|
||||
if len(ports) == 1 {
|
||||
if len(usbInterfaces) > 0 {
|
||||
return "", errors.New("unable to search for a default USB device - use -port flag, available ports are " + strings.Join(ports, ", "))
|
||||
} else if len(ports) == 1 {
|
||||
return ports[0], nil
|
||||
} else {
|
||||
return "", errors.New("multiple serial ports available - use -port flag, available ports are " + strings.Join(ports, ", "))
|
||||
@@ -1102,6 +1119,7 @@ func usage(command string) {
|
||||
fmt.Fprintln(os.Stderr, " flash: compile and flash to the device")
|
||||
fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB")
|
||||
fmt.Fprintln(os.Stderr, " lldb: run/flash and immediately enter LLDB")
|
||||
fmt.Fprintln(os.Stderr, " monitor: open communication port")
|
||||
fmt.Fprintln(os.Stderr, " env: list environment variables used during build")
|
||||
fmt.Fprintln(os.Stderr, " list: run go list using the TinyGo root")
|
||||
fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+goenv.Get("GOCACHE")+")")
|
||||
@@ -1298,6 +1316,12 @@ func main() {
|
||||
var tags buildutil.TagsFlag
|
||||
flag.Var(&tags, "tags", "a space-separated list of extra build tags")
|
||||
target := flag.String("target", "", "chip/board name or JSON target specification file")
|
||||
var stackSize uint64
|
||||
flag.Func("stack-size", "goroutine stack size (if unknown at compile time)", func(s string) error {
|
||||
size, err := bytesize.Parse(s)
|
||||
stackSize = uint64(size)
|
||||
return err
|
||||
})
|
||||
printSize := flag.String("size", "", "print sizes (none, short, full)")
|
||||
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")
|
||||
@@ -1312,6 +1336,8 @@ func main() {
|
||||
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")
|
||||
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
|
||||
monitor := flag.Bool("monitor", false, "enable serial monitor")
|
||||
baudrate := flag.Int("baudrate", 115200, "baudrate of serial monitor")
|
||||
|
||||
var flagJSON, flagDeps, flagTest bool
|
||||
if command == "help" || command == "list" || command == "info" || command == "build" {
|
||||
@@ -1378,6 +1404,7 @@ func main() {
|
||||
GOARCH: goenv.Get("GOARCH"),
|
||||
GOARM: goenv.Get("GOARM"),
|
||||
Target: *target,
|
||||
StackSize: stackSize,
|
||||
Opt: *opt,
|
||||
GC: *gc,
|
||||
PanicStrategy: *panicStrategy,
|
||||
@@ -1400,6 +1427,8 @@ func main() {
|
||||
OpenOCDCommands: ocdCommands,
|
||||
LLVMFeatures: *llvmFeatures,
|
||||
PrintJSON: flagJSON,
|
||||
Monitor: *monitor,
|
||||
BaudRate: *baudrate,
|
||||
}
|
||||
if *printCommands {
|
||||
options.PrintCommands = printCommand
|
||||
@@ -1590,6 +1619,9 @@ func main() {
|
||||
fmt.Println("FAIL")
|
||||
os.Exit(1)
|
||||
}
|
||||
case "monitor":
|
||||
err := Monitor(*port, options)
|
||||
handleCompilerError(err)
|
||||
case "targets":
|
||||
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
|
||||
entries, err := ioutil.ReadDir(dir)
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/signal"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-tty"
|
||||
"github.com/tinygo-org/tinygo/builder"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
// Monitor connects to the given port and reads/writes the serial port.
|
||||
func Monitor(port string, options *compileopts.Options) error {
|
||||
config, err := builder.NewConfig(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
wait := 300
|
||||
for i := 0; i <= wait; i++ {
|
||||
port, err = getDefaultPort(port, config.Target.SerialPort)
|
||||
if err != nil {
|
||||
if i < wait {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
br := options.BaudRate
|
||||
if br <= 0 {
|
||||
br = 115200
|
||||
}
|
||||
|
||||
wait = 300
|
||||
var p serial.Port
|
||||
for i := 0; i <= wait; i++ {
|
||||
p, err = serial.Open(port, &serial.Mode{BaudRate: br})
|
||||
if err != nil {
|
||||
if i < wait {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
tty, err := tty.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer tty.Close()
|
||||
|
||||
sig := make(chan os.Signal, 1)
|
||||
signal.Notify(sig, os.Interrupt)
|
||||
defer signal.Stop(sig)
|
||||
|
||||
go func() {
|
||||
<-sig
|
||||
tty.Close()
|
||||
os.Exit(0)
|
||||
}()
|
||||
|
||||
fmt.Printf("Connected to %s. Press Ctrl-C to exit.\n", port)
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 100*1024)
|
||||
for {
|
||||
n, err := p.Read(buf)
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("read error: %w", err)
|
||||
return
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
continue
|
||||
}
|
||||
fmt.Printf("%v", string(buf[:n]))
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
for {
|
||||
r, err := tty.ReadRune()
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
if r == 0 {
|
||||
continue
|
||||
}
|
||||
p.Write([]byte(string(r)))
|
||||
}
|
||||
}()
|
||||
|
||||
return <-errCh
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build stm32 || (sam && atsamd51) || (sam && atsame5x)
|
||||
// +build stm32 sam,atsamd51 sam,atsame5x
|
||||
//go:build nrf || stm32 || (sam && atsamd51) || (sam && atsame5x)
|
||||
// +build nrf stm32 sam,atsamd51 sam,atsame5x
|
||||
|
||||
package rand
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
// Reads multiple rp2040 ADC channels concurrently. Including the internal temperature sensor
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
type celsius float32
|
||||
|
||||
func (c celsius) String() string {
|
||||
return fmt.Sprintf("%4.1f℃", c)
|
||||
}
|
||||
|
||||
// rp2040 ADC is 12 bits. Reading are shifted <<4 to fill the 16-bit range.
|
||||
var adcReading [3]uint16
|
||||
|
||||
func readADC(a machine.ADC, w time.Duration, i int) {
|
||||
for {
|
||||
adcReading[i] = a.Get()
|
||||
time.Sleep(w)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
machine.InitADC()
|
||||
a0 := machine.ADC{machine.ADC0} // GPIO26 input
|
||||
a1 := machine.ADC{machine.ADC1} // GPIO27 input
|
||||
a2 := machine.ADC{machine.ADC2} // GPIO28 input
|
||||
t := machine.ADC_TEMP_SENSOR // Internal Temperature sensor
|
||||
// Configure sets the GPIOs to PinAnalog mode
|
||||
a0.Configure(machine.ADCConfig{})
|
||||
a1.Configure(machine.ADCConfig{})
|
||||
a2.Configure(machine.ADCConfig{})
|
||||
// Configure powers on the temperature sensor
|
||||
t.Configure(machine.ADCConfig{})
|
||||
|
||||
// Safe to read concurrently
|
||||
go readADC(a0, 10*time.Millisecond, 0)
|
||||
go readADC(a1, 17*time.Millisecond, 1)
|
||||
go readADC(a2, 29*time.Millisecond, 2)
|
||||
|
||||
for {
|
||||
fmt.Printf("ADC0: %5d ADC1: %5d ADC2: %5d Temp: %v\n\r", adcReading[0], adcReading[1], adcReading[2], celsius(float32(t.ReadTemperature())/1000))
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// Read the internal temperature sensor of the chip.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
type celsius float32
|
||||
|
||||
func (c celsius) String() string {
|
||||
return fmt.Sprintf("%4.1f℃", c)
|
||||
}
|
||||
|
||||
func main() {
|
||||
for {
|
||||
temp := celsius(float32(machine.ReadTemperature()) / 1000)
|
||||
println("temperature:", temp.String())
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
@@ -21,12 +21,14 @@ $ tinygo build -o ./wasm.wasm -target wasm ./main/main.go
|
||||
This creates a `wasm.wasm` file, which we can load in JavaScript and execute in
|
||||
a browser.
|
||||
|
||||
This examples folder contains two examples that can be built using `make`:
|
||||
|
||||
```bash
|
||||
$ make export
|
||||
```
|
||||
Next, choose which example you want to use:
|
||||
* [callback](callback): Defines and configures callbacks in Wasm.
|
||||
* [export](export): Defines callbacks in Wasm, but configures them in JavaScript.
|
||||
* [invoke](invoke): Invokes a function defined in JavaScript from Wasm.
|
||||
* [main](main): Prints a message to the JavaScript console from Wasm.
|
||||
* [slices](slices): Splits an Array defined in JavaScript from Wasm.
|
||||
|
||||
Let's say you chose [main](main), you'd build it like so:
|
||||
```bash
|
||||
$ make main
|
||||
```
|
||||
@@ -42,12 +44,8 @@ Serving ./html on http://localhost:8080
|
||||
|
||||
Use your web browser to visit http://localhost:8080.
|
||||
|
||||
* The wasm "export" example displays a simple math equation using HTML, with
|
||||
the result calculated dynamically using WebAssembly. Changing any of the
|
||||
values on the left hand side triggers the exported wasm `update` function to
|
||||
recalculate the result.
|
||||
* The wasm "main" example uses `println` to write to your browser JavaScript
|
||||
console. You may need to open the browser development tools console to see it.
|
||||
* Tip: Open the browser development tools (e.g. Right-click, Inspect in
|
||||
FireFox) to see console output.
|
||||
|
||||
## How it works
|
||||
|
||||
|
||||
@@ -8,10 +8,12 @@ import (
|
||||
var a, b int
|
||||
|
||||
func main() {
|
||||
wait := make(chan struct{}, 0)
|
||||
document := js.Global().Get("document")
|
||||
document.Call("getElementById", "a").Set("oninput", updater(&a))
|
||||
document.Call("getElementById", "b").Set("oninput", updater(&b))
|
||||
update()
|
||||
<-wait
|
||||
}
|
||||
|
||||
func updater(n *int) js.Func {
|
||||
|
||||
@@ -2,12 +2,16 @@
|
||||
|
||||
.functype start_unwind (i32) -> ()
|
||||
.import_module start_unwind, asyncify
|
||||
.import_name start_unwind, start_unwind
|
||||
.functype stop_unwind () -> ()
|
||||
.import_module stop_unwind, asyncify
|
||||
.import_name stop_unwind, stop_unwind
|
||||
.functype start_rewind (i32) -> ()
|
||||
.import_module start_rewind, asyncify
|
||||
.import_name start_rewind, start_rewind
|
||||
.functype stop_rewind () -> ()
|
||||
.import_module stop_rewind, asyncify
|
||||
.import_name stop_rewind, stop_rewind
|
||||
|
||||
.global tinygo_unwind
|
||||
.hidden tinygo_unwind
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
// Windows on amd64 has a slightly different ABI than other (*nix) systems.
|
||||
// Therefore, assembly functions need to be tweaked slightly.
|
||||
//
|
||||
// The calling convention is described here:
|
||||
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
|
||||
|
||||
.section .text.tinygo_startTask,"ax"
|
||||
.global tinygo_startTask
|
||||
@@ -17,8 +20,9 @@ tinygo_startTask:
|
||||
// Branch to the "goroutine start" function.
|
||||
callq *%r12
|
||||
|
||||
// After return, exit this goroutine. This is a tail call.
|
||||
jmp tinygo_pause
|
||||
// After return, exit this goroutine.
|
||||
// This has to be a call, not a jump, to keep the stack correctly aligned.
|
||||
callq tinygo_pause
|
||||
|
||||
.global tinygo_swapTask
|
||||
.section .text.tinygo_swapTask,"ax"
|
||||
@@ -35,6 +39,17 @@ tinygo_swapTask:
|
||||
pushq %rsi
|
||||
pushq %rdi
|
||||
pushq %rbp
|
||||
sub $160, %rsp
|
||||
movaps %xmm6, 144(%rsp)
|
||||
movaps %xmm7, 128(%rsp)
|
||||
movaps %xmm8, 112(%rsp)
|
||||
movaps %xmm9, 96(%rsp)
|
||||
movaps %xmm10, 80(%rsp)
|
||||
movaps %xmm11, 64(%rsp)
|
||||
movaps %xmm12, 48(%rsp)
|
||||
movaps %xmm13, 32(%rsp)
|
||||
movaps %xmm14, 16(%rsp)
|
||||
movaps %xmm15, 0(%rsp)
|
||||
pushq %rbx
|
||||
|
||||
// Save the current stack pointer in oldStack.
|
||||
@@ -45,6 +60,17 @@ tinygo_swapTask:
|
||||
|
||||
// Load saved register from the new stack.
|
||||
popq %rbx
|
||||
movaps 0(%rsp), %xmm15
|
||||
movaps 16(%rsp), %xmm14
|
||||
movaps 32(%rsp), %xmm13
|
||||
movaps 48(%rsp), %xmm12
|
||||
movaps 64(%rsp), %xmm11
|
||||
movaps 80(%rsp), %xmm10
|
||||
movaps 96(%rsp), %xmm9
|
||||
movaps 112(%rsp), %xmm8
|
||||
movaps 128(%rsp), %xmm7
|
||||
movaps 144(%rsp), %xmm6
|
||||
add $160, %rsp
|
||||
popq %rbp
|
||||
popq %rdi
|
||||
popq %rsi
|
||||
|
||||
@@ -13,15 +13,34 @@ var systemStack uintptr
|
||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||
// switching between tasks. Also see task_stack_amd64_windows.S that relies on
|
||||
// the exact layout of this struct.
|
||||
// The calling convention is described here:
|
||||
// https://docs.microsoft.com/en-us/cpp/build/x64-calling-convention?view=msvc-170
|
||||
// Most importantly, these are the registers we need to save/restore:
|
||||
//
|
||||
// > The x64 ABI considers registers RBX, RBP, RDI, RSI, RSP, R12, R13, R14,
|
||||
// > R15, and XMM6-XMM15 nonvolatile. They must be saved and restored by a
|
||||
// > function that uses them.
|
||||
type calleeSavedRegs struct {
|
||||
rbx uintptr
|
||||
rbp uintptr
|
||||
rdi uintptr
|
||||
rsi uintptr
|
||||
r12 uintptr
|
||||
r13 uintptr
|
||||
r14 uintptr
|
||||
r15 uintptr
|
||||
// Note: rbx is placed here so that the stack is correctly aligned when
|
||||
// loading/storing the xmm registers.
|
||||
rbx uintptr
|
||||
xmm15 [2]uint64
|
||||
xmm14 [2]uint64
|
||||
xmm13 [2]uint64
|
||||
xmm12 [2]uint64
|
||||
xmm11 [2]uint64
|
||||
xmm10 [2]uint64
|
||||
xmm9 [2]uint64
|
||||
xmm8 [2]uint64
|
||||
xmm7 [2]uint64
|
||||
xmm6 [2]uint64
|
||||
rbp uintptr
|
||||
rdi uintptr
|
||||
rsi uintptr
|
||||
r12 uintptr
|
||||
r13 uintptr
|
||||
r14 uintptr
|
||||
r15 uintptr
|
||||
|
||||
pc uintptr
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0x07738135
|
||||
const resetMagicValue = 0x07738135
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0x07738135
|
||||
const resetMagicValue = 0x07738135
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0x07738135
|
||||
const resetMagicValue = 0x07738135
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0x07738135
|
||||
const resetMagicValue = 0x07738135
|
||||
|
||||
// GPIO Pins - Digital Low
|
||||
const (
|
||||
|
||||
@@ -12,9 +12,9 @@ const (
|
||||
|
||||
const (
|
||||
PB0 = portB + 0
|
||||
PB1 = portB + 1
|
||||
PB2 = portB + 2
|
||||
PB3 = portB + 3
|
||||
PB1 = portB + 1 // peripherals: Timer1 channel A
|
||||
PB2 = portB + 2 // peripherals: Timer1 channel B
|
||||
PB3 = portB + 3 // peripherals: Timer2 channel A
|
||||
PB4 = portB + 4
|
||||
PB5 = portB + 5
|
||||
PB6 = portB + 6
|
||||
@@ -30,9 +30,9 @@ const (
|
||||
PD0 = portD + 0
|
||||
PD1 = portD + 1
|
||||
PD2 = portD + 2
|
||||
PD3 = portD + 3
|
||||
PD3 = portD + 3 // peripherals: Timer2 channel B
|
||||
PD4 = portD + 4
|
||||
PD5 = portD + 5
|
||||
PD6 = portD + 6
|
||||
PD5 = portD + 5 // peripherals: Timer0 channel B
|
||||
PD6 = portD + 6 // peripherals: Timer0 channel A
|
||||
PD7 = portD + 7
|
||||
)
|
||||
|
||||
@@ -10,38 +10,38 @@ func CPUFrequency() uint32 {
|
||||
|
||||
// Hardware pins
|
||||
const (
|
||||
PA00 Pin = 0
|
||||
PA01 Pin = 1
|
||||
PA00 Pin = 0 // peripherals: TCC2 channel 0
|
||||
PA01 Pin = 1 // peripherals: TCC2 channel 1
|
||||
PA02 Pin = 2
|
||||
PA03 Pin = 3
|
||||
PA04 Pin = 4
|
||||
PA05 Pin = 5
|
||||
PA06 Pin = 6
|
||||
PA07 Pin = 7
|
||||
PA08 Pin = 8
|
||||
PA09 Pin = 9
|
||||
PA10 Pin = 10
|
||||
PA11 Pin = 11
|
||||
PA12 Pin = 12
|
||||
PA13 Pin = 13
|
||||
PA14 Pin = 14
|
||||
PA15 Pin = 15
|
||||
PA16 Pin = 16
|
||||
PA17 Pin = 17
|
||||
PA18 Pin = 18
|
||||
PA19 Pin = 19
|
||||
PA20 Pin = 20
|
||||
PA21 Pin = 21
|
||||
PA22 Pin = 22
|
||||
PA23 Pin = 23
|
||||
PA24 Pin = 24
|
||||
PA25 Pin = 25
|
||||
PA04 Pin = 4 // peripherals: TCC0 channel 0
|
||||
PA05 Pin = 5 // peripherals: TCC0 channel 1
|
||||
PA06 Pin = 6 // peripherals: TCC1 channel 0
|
||||
PA07 Pin = 7 // peripherals: TCC1 channel 1
|
||||
PA08 Pin = 8 // peripherals: TCC0 channel 0, TCC1 channel 2
|
||||
PA09 Pin = 9 // peripherals: TCC0 channel 1, TCC1 channel 3
|
||||
PA10 Pin = 10 // peripherals: TCC1 channel 0, TCC0 channel 2
|
||||
PA11 Pin = 11 // peripherals: TCC1 channel 1, TCC0 channel 3
|
||||
PA12 Pin = 12 // peripherals: TCC2 channel 0, TCC0 channel 2
|
||||
PA13 Pin = 13 // peripherals: TCC2 channel 1, TCC0 channel 3
|
||||
PA14 Pin = 14 // peripherals: TCC0 channel 0
|
||||
PA15 Pin = 15 // peripherals: TCC0 channel 1
|
||||
PA16 Pin = 16 // peripherals: TCC2 channel 0, TCC0 channel 2
|
||||
PA17 Pin = 17 // peripherals: TCC2 channel 1, TCC0 channel 3
|
||||
PA18 Pin = 18 // peripherals: TCC0 channel 2
|
||||
PA19 Pin = 19 // peripherals: TCC0 channel 3
|
||||
PA20 Pin = 20 // peripherals: TCC0 channel 2
|
||||
PA21 Pin = 21 // peripherals: TCC0 channel 3
|
||||
PA22 Pin = 22 // peripherals: TCC0 channel 0
|
||||
PA23 Pin = 23 // peripherals: TCC0 channel 1
|
||||
PA24 Pin = 24 // peripherals: TCC1 channel 2
|
||||
PA25 Pin = 25 // peripherals: TCC1 channel 3
|
||||
PA26 Pin = 26
|
||||
PA27 Pin = 27
|
||||
PA28 Pin = 28
|
||||
PA29 Pin = 29
|
||||
PA30 Pin = 30
|
||||
PA31 Pin = 31
|
||||
PA30 Pin = 30 // peripherals: TCC1 channel 0
|
||||
PA31 Pin = 31 // peripherals: TCC1 channel 1
|
||||
PB00 Pin = 32
|
||||
PB01 Pin = 33
|
||||
PB02 Pin = 34
|
||||
@@ -52,14 +52,14 @@ const (
|
||||
PB07 Pin = 39
|
||||
PB08 Pin = 40
|
||||
PB09 Pin = 41
|
||||
PB10 Pin = 42
|
||||
PB11 Pin = 43
|
||||
PB12 Pin = 44
|
||||
PB13 Pin = 45
|
||||
PB10 Pin = 42 // peripherals: TCC0 channel 0
|
||||
PB11 Pin = 43 // peripherals: TCC0 channel 1
|
||||
PB12 Pin = 44 // peripherals: TCC0 channel 2
|
||||
PB13 Pin = 45 // peripherals: TCC0 channel 3
|
||||
PB14 Pin = 46
|
||||
PB15 Pin = 47
|
||||
PB16 Pin = 48
|
||||
PB17 Pin = 49
|
||||
PB16 Pin = 48 // peripherals: TCC0 channel 0
|
||||
PB17 Pin = 49 // peripherals: TCC0 channel 1
|
||||
PB18 Pin = 50
|
||||
PB19 Pin = 51
|
||||
PB20 Pin = 52
|
||||
@@ -72,6 +72,6 @@ const (
|
||||
PB27 Pin = 59
|
||||
PB28 Pin = 60
|
||||
PB29 Pin = 61
|
||||
PB30 Pin = 62
|
||||
PB31 Pin = 63
|
||||
PB30 Pin = 62 // peripherals: TCC0 channel 0, TCC1 channel 2
|
||||
PB31 Pin = 63 // peripherals: TCC0 channel 1, TCC1 channel 3
|
||||
)
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
// Definition for compatibility, but not used
|
||||
const RESET_MAGIC_VALUE = 0x00000000
|
||||
const resetMagicValue = 0x00000000
|
||||
|
||||
const (
|
||||
LED = PC18
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -245,7 +245,7 @@ const (
|
||||
|
||||
// Other peripheral constants
|
||||
const (
|
||||
RESET_MAGIC_VALUE = 0xF01669EF // Used to reset into bootloader
|
||||
resetMagicValue = 0xF01669EF // Used to reset into bootloader
|
||||
)
|
||||
|
||||
// USB CDC pins
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xF01669EF
|
||||
const resetMagicValue = 0xF01669EF
|
||||
|
||||
// Digital pins
|
||||
const (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0x07738135
|
||||
const resetMagicValue = 0x07738135
|
||||
|
||||
// Note: On the P1AM-100, pins D8, D9, D10, A3, and A4 are used for
|
||||
// communication with the base controller.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
//go:build qtpy_rp2040
|
||||
// +build qtpy_rp2040
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
const xoscFreq = 12 // MHz
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
SDA = GPIO24
|
||||
SCL = GPIO25
|
||||
TX = GPIO20
|
||||
MO = GPIO3
|
||||
MOSI = GPIO3
|
||||
MI = GPIO4
|
||||
MISO = GPIO4
|
||||
SCK = GPIO6
|
||||
RX = GPIO5
|
||||
|
||||
QT_SCL1 = GPIO23
|
||||
QT_SDA1 = GPIO22
|
||||
)
|
||||
|
||||
// Analog pins
|
||||
const (
|
||||
A0 = GPIO29
|
||||
A1 = GPIO28
|
||||
A2 = GPIO27
|
||||
A3 = GPIO26
|
||||
)
|
||||
|
||||
const (
|
||||
NEOPIXEL = GPIO12
|
||||
WS2812 = GPIO12
|
||||
NEOPIXEL_POWER = GPIO11
|
||||
)
|
||||
|
||||
// I2C Pins.
|
||||
const (
|
||||
I2C0_SDA_PIN = GPIO24
|
||||
I2C0_SCL_PIN = GPIO25
|
||||
|
||||
I2C1_SDA_PIN = GPIO26
|
||||
I2C1_SCL_PIN = GPIO27
|
||||
|
||||
I2C1_QT_SDA_PIN = GPIO22
|
||||
I2C1_QT_SCL_PIN = GPIO23
|
||||
|
||||
SDA_PIN = GPIO24
|
||||
SCL_PIN = GPIO25
|
||||
)
|
||||
|
||||
// SPI default pins
|
||||
const (
|
||||
// Default Serial Clock Bus 0 for SPI communications
|
||||
SPI0_SCK_PIN = GPIO6
|
||||
// Default Serial Out Bus 0 for SPI communications
|
||||
SPI0_SDO_PIN = GPIO3 // Tx
|
||||
// Default Serial In Bus 0 for SPI communications
|
||||
SPI0_SDI_PIN = GPIO4 // Rx
|
||||
SPI0_CS = GPIO5
|
||||
|
||||
// Default Serial Clock Bus 1 for SPI communications
|
||||
SPI1_SCK_PIN = GPIO26
|
||||
// Default Serial Out Bus 1 for SPI communications
|
||||
SPI1_SDO_PIN = GPIO27 // Tx
|
||||
// Default Serial In Bus 1 for SPI communications
|
||||
SPI1_SDI_PIN = GPIO24 // Rx
|
||||
SPI1_CS = GPIO25
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO28
|
||||
UART0_RX_PIN = GPIO29
|
||||
UART1_TX_PIN = GPIO20
|
||||
UART1_RX_PIN = GPIO5
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART0,
|
||||
}
|
||||
|
||||
UART1 = &_UART1
|
||||
_UART1 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART1,
|
||||
}
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||
UART1.Interrupt = interrupt.New(rp.IRQ_UART1_IRQ, _UART1.handleInterrupt)
|
||||
}
|
||||
|
||||
// USB identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "QT Py RP2040"
|
||||
usb_STRING_MANUFACTURER = "Adafruit"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x239A
|
||||
usb_PID uint16 = 0x80F7
|
||||
)
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
const (
|
||||
ADC0 = A0
|
||||
|
||||
@@ -104,7 +104,7 @@ const (
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x2886
|
||||
usb_PID uint16 = 0x0045
|
||||
usb_PID uint16 = 0x8045
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
package machine
|
||||
|
||||
// used to reset into bootloader
|
||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||
const resetMagicValue = 0xf01669ef
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
)
|
||||
|
||||
// TWI_FREQ is the I2C bus speed. Normally either 100 kHz, or 400 kHz for high-speed bus.
|
||||
//
|
||||
// Deprecated: use 100 * machine.KHz or 400 * machine.KHz instead.
|
||||
const (
|
||||
TWI_FREQ_100KHZ = 100000
|
||||
TWI_FREQ_400KHZ = 400000
|
||||
|
||||
@@ -18,6 +18,13 @@ var (
|
||||
// particular chip but instead runs in WebAssembly for example.
|
||||
const Device = deviceName
|
||||
|
||||
// Generic constants.
|
||||
const (
|
||||
KHz = 1000
|
||||
MHz = 1000_000
|
||||
GHz = 1000_000_000
|
||||
)
|
||||
|
||||
// PinMode sets the direction and pull mode of the pin. For example, PinOutput
|
||||
// sets the pin as an output and PinInputPullup sets the pin as an input with a
|
||||
// pull-up.
|
||||
|
||||
@@ -26,7 +26,7 @@ type I2CConfig struct {
|
||||
func (i2c *I2C) Configure(config I2CConfig) error {
|
||||
// Default I2C bus speed is 100 kHz.
|
||||
if config.Frequency == 0 {
|
||||
config.Frequency = TWI_FREQ_100KHZ
|
||||
config.Frequency = 100 * KHz
|
||||
}
|
||||
|
||||
// Activate internal pullups for twi.
|
||||
|
||||
@@ -38,10 +38,10 @@ const (
|
||||
PB1 = portB + 1
|
||||
PB2 = portB + 2
|
||||
PB3 = portB + 3
|
||||
PB4 = portB + 4
|
||||
PB5 = portB + 5
|
||||
PB6 = portB + 6
|
||||
PB7 = portB + 7
|
||||
PB4 = portB + 4 // peripherals: Timer2 channel A
|
||||
PB5 = portB + 5 // peripherals: Timer1 channel A
|
||||
PB6 = portB + 6 // peripherals: Timer1 channel B
|
||||
PB7 = portB + 7 // peripherals: Timer0 channel A
|
||||
PC0 = portC + 0
|
||||
PC1 = portC + 1
|
||||
PC2 = portC + 2
|
||||
@@ -57,9 +57,9 @@ const (
|
||||
PD7 = portD + 7
|
||||
PE0 = portE + 0
|
||||
PE1 = portE + 1
|
||||
PE3 = portE + 3
|
||||
PE4 = portE + 4
|
||||
PE5 = portE + 5
|
||||
PE3 = portE + 3 // peripherals: Timer3 channel A
|
||||
PE4 = portE + 4 // peripherals: Timer3 channel B
|
||||
PE5 = portE + 5 // peripherals: Timer3 channel C
|
||||
PE6 = portE + 6
|
||||
PF0 = portF + 0
|
||||
PF1 = portF + 1
|
||||
@@ -72,13 +72,13 @@ const (
|
||||
PG0 = portG + 0
|
||||
PG1 = portG + 1
|
||||
PG2 = portG + 2
|
||||
PG5 = portG + 5
|
||||
PG5 = portG + 5 // peripherals: Timer0 channel B
|
||||
PH0 = portH + 0
|
||||
PH1 = portH + 1
|
||||
PH3 = portH + 3
|
||||
PH4 = portH + 4
|
||||
PH5 = portH + 5
|
||||
PH6 = portH + 6
|
||||
PH3 = portH + 3 // peripherals: Timer4 channel A
|
||||
PH4 = portH + 4 // peripherals: Timer4 channel B
|
||||
PH5 = portH + 5 // peripherals: Timer4 channel C
|
||||
PH6 = portH + 6 // peripherals: Timer0 channel B
|
||||
PJ0 = portJ + 0
|
||||
PJ1 = portJ + 1
|
||||
PK0 = portK + 0
|
||||
@@ -92,9 +92,9 @@ const (
|
||||
PL0 = portL + 0
|
||||
PL1 = portL + 1
|
||||
PL2 = portL + 2
|
||||
PL3 = portL + 3
|
||||
PL4 = portL + 4
|
||||
PL5 = portL + 5
|
||||
PL3 = portL + 3 // peripherals: Timer5 channel A
|
||||
PL4 = portL + 4 // peripherals: Timer5 channel B
|
||||
PL5 = portL + 5 // peripherals: Timer5 channel C
|
||||
PL6 = portL + 6
|
||||
PL7 = portL + 7
|
||||
)
|
||||
|
||||
@@ -10,7 +10,6 @@ package machine
|
||||
import (
|
||||
"device/arm"
|
||||
"device/sam"
|
||||
"errors"
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -677,7 +676,7 @@ const i2cTimeout = 1000
|
||||
func (i2c *I2C) Configure(config I2CConfig) error {
|
||||
// Default I2C bus speed is 100 kHz.
|
||||
if config.Frequency == 0 {
|
||||
config.Frequency = TWI_FREQ_100KHZ
|
||||
config.Frequency = 100 * KHz
|
||||
}
|
||||
if config.SDA == 0 && config.SCL == 0 {
|
||||
config.SDA = SDA_PIN
|
||||
@@ -1274,10 +1273,6 @@ func (spi SPI) Transfer(w byte) (byte, error) {
|
||||
return byte(spi.Bus.DATA.Get()), nil
|
||||
}
|
||||
|
||||
var (
|
||||
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
|
||||
)
|
||||
|
||||
// Tx handles read/write operation for SPI interface. Since SPI is a syncronous write/read
|
||||
// interface, there must always be the same number of bytes written as bytes read.
|
||||
// The Tx method knows about this, and offers a few different ways of calling it.
|
||||
@@ -1740,7 +1735,7 @@ func EnterBootloader() {
|
||||
|
||||
// Perform magic reset into bootloader, as mentioned in
|
||||
// https://github.com/arduino/ArduinoCore-samd/issues/197
|
||||
*(*uint32)(unsafe.Pointer(uintptr(0x20007FFC))) = RESET_MAGIC_VALUE
|
||||
*(*uint32)(unsafe.Pointer(uintptr(0x20007FFC))) = resetMagicValue
|
||||
|
||||
arm.SystemReset()
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ package machine
|
||||
import (
|
||||
"device/arm"
|
||||
"device/sam"
|
||||
"errors"
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -78,86 +77,86 @@ const (
|
||||
PA05 Pin = 5
|
||||
PA06 Pin = 6
|
||||
PA07 Pin = 7
|
||||
PA08 Pin = 8
|
||||
PA09 Pin = 9
|
||||
PA10 Pin = 10
|
||||
PA11 Pin = 11
|
||||
PA12 Pin = 12
|
||||
PA13 Pin = 13
|
||||
PA14 Pin = 14
|
||||
PA15 Pin = 15
|
||||
PA16 Pin = 16
|
||||
PA17 Pin = 17
|
||||
PA18 Pin = 18
|
||||
PA19 Pin = 19
|
||||
PA20 Pin = 20
|
||||
PA21 Pin = 21
|
||||
PA22 Pin = 22
|
||||
PA23 Pin = 23
|
||||
PA24 Pin = 24
|
||||
PA25 Pin = 25
|
||||
PA08 Pin = 8 // peripherals: TCC0 channel 0, TCC1 channel 4
|
||||
PA09 Pin = 9 // peripherals: TCC0 channel 1, TCC1 channel 5
|
||||
PA10 Pin = 10 // peripherals: TCC0 channel 2, TCC1 channel 6
|
||||
PA11 Pin = 11 // peripherals: TCC0 channel 3, TCC1 channel 7
|
||||
PA12 Pin = 12 // peripherals: TCC0 channel 6, TCC1 channel 2
|
||||
PA13 Pin = 13 // peripherals: TCC0 channel 7, TCC1 channel 3
|
||||
PA14 Pin = 14 // peripherals: TCC2 channel 0, TCC1 channel 2
|
||||
PA15 Pin = 15 // peripherals: TCC2 channel 1, TCC1 channel 3
|
||||
PA16 Pin = 16 // peripherals: TCC1 channel 0, TCC0 channel 4
|
||||
PA17 Pin = 17 // peripherals: TCC1 channel 1, TCC0 channel 5
|
||||
PA18 Pin = 18 // peripherals: TCC1 channel 2, TCC0 channel 6
|
||||
PA19 Pin = 19 // peripherals: TCC1 channel 3, TCC0 channel 7
|
||||
PA20 Pin = 20 // peripherals: TCC1 channel 4, TCC0 channel 0
|
||||
PA21 Pin = 21 // peripherals: TCC1 channel 5, TCC0 channel 1
|
||||
PA22 Pin = 22 // peripherals: TCC1 channel 6, TCC0 channel 2
|
||||
PA23 Pin = 23 // peripherals: TCC1 channel 7, TCC0 channel 3
|
||||
PA24 Pin = 24 // peripherals: TCC2 channel 2
|
||||
PA25 Pin = 25 // peripherals: TCC2 channel 3
|
||||
PA26 Pin = 26
|
||||
PA27 Pin = 27
|
||||
PA28 Pin = 28
|
||||
PA29 Pin = 29
|
||||
PA30 Pin = 30
|
||||
PA31 Pin = 31
|
||||
PA30 Pin = 30 // peripherals: TCC2 channel 0
|
||||
PA31 Pin = 31 // peripherals: TCC2 channel 1
|
||||
PB00 Pin = 32
|
||||
PB01 Pin = 33
|
||||
PB02 Pin = 34
|
||||
PB03 Pin = 35
|
||||
PB02 Pin = 34 // peripherals: TCC2 channel 2
|
||||
PB03 Pin = 35 // peripherals: TCC2 channel 3
|
||||
PB04 Pin = 36
|
||||
PB05 Pin = 37
|
||||
PB06 Pin = 38
|
||||
PB07 Pin = 39
|
||||
PB08 Pin = 40
|
||||
PB09 Pin = 41
|
||||
PB10 Pin = 42
|
||||
PB11 Pin = 43
|
||||
PB12 Pin = 44
|
||||
PB13 Pin = 45
|
||||
PB14 Pin = 46
|
||||
PB15 Pin = 47
|
||||
PB16 Pin = 48
|
||||
PB17 Pin = 49
|
||||
PB18 Pin = 50
|
||||
PB19 Pin = 51
|
||||
PB20 Pin = 52
|
||||
PB21 Pin = 53
|
||||
PB10 Pin = 42 // peripherals: TCC0 channel 4, TCC1 channel 0
|
||||
PB11 Pin = 43 // peripherals: TCC0 channel 5, TCC1 channel 1
|
||||
PB12 Pin = 44 // peripherals: TCC3 channel 0, TCC0 channel 0
|
||||
PB13 Pin = 45 // peripherals: TCC3 channel 1, TCC0 channel 1
|
||||
PB14 Pin = 46 // peripherals: TCC4 channel 0, TCC0 channel 2
|
||||
PB15 Pin = 47 // peripherals: TCC4 channel 1, TCC0 channel 3
|
||||
PB16 Pin = 48 // peripherals: TCC3 channel 0, TCC0 channel 4
|
||||
PB17 Pin = 49 // peripherals: TCC3 channel 1, TCC0 channel 5
|
||||
PB18 Pin = 50 // peripherals: TCC1 channel 0
|
||||
PB19 Pin = 51 // peripherals: TCC1 channel 1
|
||||
PB20 Pin = 52 // peripherals: TCC1 channel 2
|
||||
PB21 Pin = 53 // peripherals: TCC1 channel 3
|
||||
PB22 Pin = 54
|
||||
PB23 Pin = 55
|
||||
PB24 Pin = 56
|
||||
PB25 Pin = 57
|
||||
PB26 Pin = 58
|
||||
PB27 Pin = 59
|
||||
PB28 Pin = 60
|
||||
PB29 Pin = 61
|
||||
PB30 Pin = 62
|
||||
PB31 Pin = 63
|
||||
PB26 Pin = 58 // peripherals: TCC1 channel 2
|
||||
PB27 Pin = 59 // peripherals: TCC1 channel 3
|
||||
PB28 Pin = 60 // peripherals: TCC1 channel 4
|
||||
PB29 Pin = 61 // peripherals: TCC1 channel 5
|
||||
PB30 Pin = 62 // peripherals: TCC4 channel 0, TCC0 channel 6
|
||||
PB31 Pin = 63 // peripherals: TCC4 channel 1, TCC0 channel 7
|
||||
PC00 Pin = 64
|
||||
PC01 Pin = 65
|
||||
PC02 Pin = 66
|
||||
PC03 Pin = 67
|
||||
PC04 Pin = 68
|
||||
PC05 Pin = 69
|
||||
PC04 Pin = 68 // peripherals: TCC0 channel 0
|
||||
PC05 Pin = 69 // peripherals: TCC0 channel 1
|
||||
PC06 Pin = 70
|
||||
PC07 Pin = 71
|
||||
PC08 Pin = 72
|
||||
PC09 Pin = 73
|
||||
PC10 Pin = 74
|
||||
PC11 Pin = 75
|
||||
PC12 Pin = 76
|
||||
PC13 Pin = 77
|
||||
PC14 Pin = 78
|
||||
PC15 Pin = 79
|
||||
PC16 Pin = 80
|
||||
PC17 Pin = 81
|
||||
PC18 Pin = 82
|
||||
PC19 Pin = 83
|
||||
PC20 Pin = 84
|
||||
PC21 Pin = 85
|
||||
PC22 Pin = 86
|
||||
PC23 Pin = 87
|
||||
PC10 Pin = 74 // peripherals: TCC0 channel 0, TCC1 channel 4
|
||||
PC11 Pin = 75 // peripherals: TCC0 channel 1, TCC1 channel 5
|
||||
PC12 Pin = 76 // peripherals: TCC0 channel 2, TCC1 channel 6
|
||||
PC13 Pin = 77 // peripherals: TCC0 channel 3, TCC1 channel 7
|
||||
PC14 Pin = 78 // peripherals: TCC0 channel 4, TCC1 channel 0
|
||||
PC15 Pin = 79 // peripherals: TCC0 channel 5, TCC1 channel 1
|
||||
PC16 Pin = 80 // peripherals: TCC0 channel 0
|
||||
PC17 Pin = 81 // peripherals: TCC0 channel 1
|
||||
PC18 Pin = 82 // peripherals: TCC0 channel 2
|
||||
PC19 Pin = 83 // peripherals: TCC0 channel 3
|
||||
PC20 Pin = 84 // peripherals: TCC0 channel 4
|
||||
PC21 Pin = 85 // peripherals: TCC0 channel 5
|
||||
PC22 Pin = 86 // peripherals: TCC0 channel 6
|
||||
PC23 Pin = 87 // peripherals: TCC0 channel 7
|
||||
PC24 Pin = 88
|
||||
PC25 Pin = 89
|
||||
PC26 Pin = 90
|
||||
@@ -174,20 +173,20 @@ const (
|
||||
PD05 Pin = 101
|
||||
PD06 Pin = 102
|
||||
PD07 Pin = 103
|
||||
PD08 Pin = 104
|
||||
PD09 Pin = 105
|
||||
PD10 Pin = 106
|
||||
PD11 Pin = 107
|
||||
PD12 Pin = 108
|
||||
PD13 Pin = 109
|
||||
PD08 Pin = 104 // peripherals: TCC0 channel 1
|
||||
PD09 Pin = 105 // peripherals: TCC0 channel 2
|
||||
PD10 Pin = 106 // peripherals: TCC0 channel 3
|
||||
PD11 Pin = 107 // peripherals: TCC0 channel 4
|
||||
PD12 Pin = 108 // peripherals: TCC0 channel 5
|
||||
PD13 Pin = 109 // peripherals: TCC0 channel 6
|
||||
PD14 Pin = 110
|
||||
PD15 Pin = 111
|
||||
PD16 Pin = 112
|
||||
PD17 Pin = 113
|
||||
PD18 Pin = 114
|
||||
PD19 Pin = 115
|
||||
PD20 Pin = 116
|
||||
PD21 Pin = 117
|
||||
PD20 Pin = 116 // peripherals: TCC1 channel 0
|
||||
PD21 Pin = 117 // peripherals: TCC1 channel 1
|
||||
PD22 Pin = 118
|
||||
PD23 Pin = 119
|
||||
PD24 Pin = 120
|
||||
@@ -1151,7 +1150,7 @@ const i2cTimeout = 1000
|
||||
func (i2c *I2C) Configure(config I2CConfig) error {
|
||||
// Default I2C bus speed is 100 kHz.
|
||||
if config.Frequency == 0 {
|
||||
config.Frequency = TWI_FREQ_100KHZ
|
||||
config.Frequency = 100 * KHz
|
||||
}
|
||||
|
||||
// Use default I2C pins if not set.
|
||||
@@ -1527,10 +1526,6 @@ func (spi SPI) Transfer(w byte) (byte, error) {
|
||||
return byte(spi.Bus.DATA.Get()), nil
|
||||
}
|
||||
|
||||
var (
|
||||
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
|
||||
)
|
||||
|
||||
// Tx handles read/write operation for SPI interface. Since SPI is a syncronous write/read
|
||||
// interface, there must always be the same number of bytes written as bytes read.
|
||||
// The Tx method knows about this, and offers a few different ways of calling it.
|
||||
@@ -1980,7 +1975,7 @@ func EnterBootloader() {
|
||||
|
||||
// Perform magic reset into bootloader, as mentioned in
|
||||
// https://github.com/arduino/ArduinoCore-samd/issues/197
|
||||
*(*uint32)(unsafe.Pointer(uintptr(0x20000000 + HSRAM_SIZE - 4))) = RESET_MAGIC_VALUE
|
||||
*(*uint32)(unsafe.Pointer(uintptr(0x20000000 + HSRAM_SIZE - 4))) = resetMagicValue
|
||||
|
||||
arm.SystemReset()
|
||||
}
|
||||
|
||||
@@ -59,12 +59,9 @@ type PinChange uint8
|
||||
|
||||
// Pin change interrupt constants for SetInterrupt.
|
||||
const (
|
||||
PinNoInterrupt PinChange = iota
|
||||
PinRising
|
||||
PinRising PinChange = iota + 1
|
||||
PinFalling
|
||||
PinToggle
|
||||
PinLowLevel
|
||||
PinHighLevel
|
||||
)
|
||||
|
||||
// Configure this pin with the given configuration.
|
||||
@@ -190,7 +187,7 @@ func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) (err error) {
|
||||
return ErrInvalidInputPin
|
||||
}
|
||||
|
||||
if callback == nil || change == PinNoInterrupt {
|
||||
if callback == nil {
|
||||
// Disable this pin interrupt
|
||||
p.pin().ClearBits(esp.GPIO_PIN_PIN_INT_TYPE_Msk | esp.GPIO_PIN_PIN_INT_ENA_Msk)
|
||||
|
||||
@@ -264,15 +261,6 @@ type UART struct {
|
||||
DataOverflowDetected bool // set when data overflow detected in UART FIFO buffer or RingBuffer
|
||||
}
|
||||
|
||||
type UARTStopBits int
|
||||
|
||||
const (
|
||||
UARTStopBits_Default UARTStopBits = iota
|
||||
UARTStopBits_1
|
||||
UARTStopBits_1_5
|
||||
UARTStopBits_2
|
||||
)
|
||||
|
||||
const (
|
||||
defaultDataBits = 8
|
||||
defaultStopBit = 1
|
||||
|
||||
@@ -231,7 +231,7 @@ type I2CConfig struct {
|
||||
func (i2c *I2C) Configure(config I2CConfig) error {
|
||||
var i2cClockFrequency uint32 = 32000000
|
||||
if config.Frequency == 0 {
|
||||
config.Frequency = TWI_FREQ_100KHZ
|
||||
config.Frequency = 100 * KHz
|
||||
}
|
||||
|
||||
if config.SDA == 0 && config.SCL == 0 {
|
||||
|
||||
@@ -23,11 +23,17 @@ type PinChange uint8
|
||||
// Pin modes.
|
||||
const (
|
||||
PinInput PinMode = iota
|
||||
PinInputPullUp
|
||||
PinInputPullDown
|
||||
PinInputPullup
|
||||
PinInputPulldown
|
||||
PinOutput
|
||||
)
|
||||
|
||||
// Deprecated: use PinInputPullup and PinInputPulldown instead.
|
||||
const (
|
||||
PinInputPullUp = PinInputPullup
|
||||
PinInputPullDown = PinInputPulldown
|
||||
)
|
||||
|
||||
// FPIOA internal pull resistors.
|
||||
const (
|
||||
fpioaPullNone fpioaPullMode = iota
|
||||
@@ -89,10 +95,10 @@ func (p Pin) Configure(config PinConfig) {
|
||||
case PinInput:
|
||||
p.setFPIOAIOPull(fpioaPullNone)
|
||||
input = true
|
||||
case PinInputPullUp:
|
||||
case PinInputPullup:
|
||||
p.setFPIOAIOPull(fpioaPullUp)
|
||||
input = true
|
||||
case PinInputPullDown:
|
||||
case PinInputPulldown:
|
||||
p.setFPIOAIOPull(fpioaPullDown)
|
||||
input = true
|
||||
case PinOutput:
|
||||
@@ -517,7 +523,7 @@ type I2CConfig struct {
|
||||
func (i2c *I2C) Configure(config I2CConfig) error {
|
||||
|
||||
if config.Frequency == 0 {
|
||||
config.Frequency = TWI_FREQ_100KHZ
|
||||
config.Frequency = 100 * KHz
|
||||
}
|
||||
|
||||
if config.SDA == 0 && config.SCL == 0 {
|
||||
|
||||
@@ -21,8 +21,8 @@ func CPUFrequency() uint32 {
|
||||
const (
|
||||
// GPIO
|
||||
PinInput PinMode = iota
|
||||
PinInputPullUp
|
||||
PinInputPullDown
|
||||
PinInputPullup
|
||||
PinInputPulldown
|
||||
PinOutput
|
||||
PinOutputOpenDrain
|
||||
PinDisable
|
||||
@@ -45,12 +45,16 @@ const (
|
||||
PinModeI2CSCL
|
||||
)
|
||||
|
||||
// Deprecated: use PinInputPullup and PinInputPulldown instead.
|
||||
const (
|
||||
PinInputPullUp = PinInputPullup
|
||||
PinInputPullDown = PinInputPulldown
|
||||
)
|
||||
|
||||
type PinChange uint8
|
||||
|
||||
const (
|
||||
PinLow PinChange = iota
|
||||
PinHigh
|
||||
PinRising
|
||||
PinRising PinChange = iota + 2
|
||||
PinFalling
|
||||
PinToggle
|
||||
)
|
||||
@@ -259,11 +263,11 @@ func (p Pin) Configure(config PinConfig) {
|
||||
gpio.GDIR.ClearBits(p.getMask())
|
||||
pad.Set(dse(7))
|
||||
|
||||
case PinInputPullUp:
|
||||
case PinInputPullup:
|
||||
gpio.GDIR.ClearBits(p.getMask())
|
||||
pad.Set(dse(7) | pke | pue | pup(3) | hys)
|
||||
|
||||
case PinInputPullDown:
|
||||
case PinInputPulldown:
|
||||
gpio.GDIR.ClearBits(p.getMask())
|
||||
pad.Set(dse(7) | pke | pue | hys)
|
||||
|
||||
@@ -387,7 +391,7 @@ func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
|
||||
mask := p.getMask()
|
||||
if nil != callback {
|
||||
switch change {
|
||||
case PinLow, PinHigh, PinRising, PinFalling:
|
||||
case PinRising, PinFalling:
|
||||
gpio.EDGE_SEL.ClearBits(mask)
|
||||
var reg *volatile.Register32
|
||||
var pos uint8
|
||||
@@ -746,7 +750,7 @@ func (p Pin) getMuxMode(config PinConfig) uint32 {
|
||||
switch config.Mode {
|
||||
|
||||
// GPIO
|
||||
case PinInput, PinInputPullUp, PinInputPullDown,
|
||||
case PinInput, PinInputPullup, PinInputPulldown,
|
||||
PinOutput, PinOutputOpenDrain, PinDisable:
|
||||
mode := uint32(0x5) // GPIO is always alternate function 5
|
||||
if forcePath {
|
||||
|
||||
@@ -10,15 +10,6 @@ import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
TWI_FREQ_BUS = 24000000 // LPI2C root clock is on 24 MHz OSC
|
||||
TWI_FREQ_100KHZ = 100000 // StandardMode (100 kHz)
|
||||
TWI_FREQ_400KHZ = 400000 // FastMode (400 kHz)
|
||||
TWI_FREQ_1MHZ = 1000000 // FastModePlus (1 MHz)
|
||||
TWI_FREQ_5MHZ = 5000000 // UltraFastMode (5 MHz)
|
||||
TWI_FREQ_DEFAULT = TWI_FREQ_100KHZ // default to StandardMode (100 kHz)
|
||||
)
|
||||
|
||||
var (
|
||||
errI2CWriteTimeout = errors.New("I2C timeout during write")
|
||||
errI2CReadTimeout = errors.New("I2C timeout during read")
|
||||
@@ -174,7 +165,7 @@ func (i2c *I2C) Configure(config I2CConfig) {
|
||||
|
||||
freq := config.Frequency
|
||||
if 0 == freq {
|
||||
freq = TWI_FREQ_DEFAULT
|
||||
freq = 100 * KHz
|
||||
}
|
||||
|
||||
// reset clock and registers, and enable LPI2C module interface
|
||||
@@ -305,7 +296,7 @@ func (i2c *I2C) setFrequency(freq uint32) {
|
||||
wasEnabled := i2c.Bus.MCR.HasBits(nxp.LPI2C_MCR_MEN)
|
||||
i2c.Bus.MCR.ClearBits(nxp.LPI2C_MCR_MEN)
|
||||
|
||||
// baud rate = (TWI_FREQ_BUS/(2^pre))/(CLKLO+1 + CLKHI+1 + FLOOR((2+FILTSCL)/(2^pre)))
|
||||
// baud rate = (24MHz/(2^pre))/(CLKLO+1 + CLKHI+1 + FLOOR((2+FILTSCL)/(2^pre)))
|
||||
// assume: CLKLO=2*CLKHI, SETHOLD=CLKHI, DATAVD=CLKHI/2
|
||||
for pre := uint32(1); pre <= 128; pre *= 2 {
|
||||
if bestError == 0 {
|
||||
@@ -314,9 +305,9 @@ func (i2c *I2C) setFrequency(freq uint32) {
|
||||
for clkHi := uint32(1); clkHi < 32; clkHi++ {
|
||||
var absError, rate uint32
|
||||
if clkHi == 1 {
|
||||
rate = (TWI_FREQ_BUS / pre) / (1 + 3 + 2 + 2/pre)
|
||||
rate = (24 * MHz / pre) / (1 + 3 + 2 + 2/pre)
|
||||
} else {
|
||||
rate = (TWI_FREQ_BUS / pre) / (3*clkHi + 2 + 2/pre)
|
||||
rate = (24 * MHz / pre) / (3*clkHi + 2 + 2/pre)
|
||||
}
|
||||
if freq > rate {
|
||||
absError = freq - rate
|
||||
@@ -370,15 +361,15 @@ func (i2c *I2C) setFrequency(freq uint32) {
|
||||
mcfgr2, mcfgr3 uint32
|
||||
)
|
||||
const i2cClockStretchTimeout = 15000 // microseconds
|
||||
if freq >= TWI_FREQ_5MHZ {
|
||||
if freq >= 5*MHz {
|
||||
// I2C UltraFastMode 5 MHz
|
||||
mcfgr2 = 0 // disable glitch filters and timeout for UltraFastMode
|
||||
mcfgr3 = 0 //
|
||||
} else if freq >= TWI_FREQ_1MHZ {
|
||||
} else if freq >= 1*MHz {
|
||||
// I2C FastModePlus 1 MHz
|
||||
mcfgr2 = filtsda(1) | filtscl(1) | busidle(2400) // 100us timeout
|
||||
mcfgr3 = pinlow(i2cClockStretchTimeout*24/256 + 1)
|
||||
} else if freq >= TWI_FREQ_400KHZ {
|
||||
} else if freq >= 400*KHz {
|
||||
// I2C FastMode 400 kHz
|
||||
mcfgr2 = filtsda(2) | filtscl(2) | busidle(3600) // 150us timeout
|
||||
mcfgr3 = pinlow(i2cClockStretchTimeout*24/256 + 1)
|
||||
|
||||
@@ -159,8 +159,8 @@ func (uart *UART) Disable() {
|
||||
uart.Bus.CTRL.ClearBits(nxp.LPUART_CTRL_TE | nxp.LPUART_CTRL_RE)
|
||||
|
||||
// put pins back into GPIO mode
|
||||
uart.rx.Configure(PinConfig{Mode: PinInputPullUp})
|
||||
uart.tx.Configure(PinConfig{Mode: PinInputPullUp})
|
||||
uart.rx.Configure(PinConfig{Mode: PinInputPullup})
|
||||
uart.tx.Configure(PinConfig{Mode: PinInputPullup})
|
||||
}
|
||||
uart.configured = false
|
||||
}
|
||||
|
||||
@@ -5,15 +5,10 @@ package machine
|
||||
|
||||
import (
|
||||
"device/nrf"
|
||||
"errors"
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
|
||||
)
|
||||
|
||||
const deviceName = nrf.Device
|
||||
|
||||
const (
|
||||
@@ -230,7 +225,7 @@ func (i2c *I2C) Configure(config I2CConfig) error {
|
||||
|
||||
// Default I2C bus speed is 100 kHz.
|
||||
if config.Frequency == 0 {
|
||||
config.Frequency = TWI_FREQ_100KHZ
|
||||
config.Frequency = 100 * KHz
|
||||
}
|
||||
// Default I2C pins if not set.
|
||||
if config.SDA == 0 && config.SCL == 0 {
|
||||
@@ -253,7 +248,7 @@ func (i2c *I2C) Configure(config I2CConfig) error {
|
||||
(nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) |
|
||||
(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos))
|
||||
|
||||
if config.Frequency == TWI_FREQ_400KHZ {
|
||||
if config.Frequency >= 400*KHz {
|
||||
i2c.Bus.FREQUENCY.Set(nrf.TWI_FREQUENCY_FREQUENCY_K400)
|
||||
} else {
|
||||
i2c.Bus.FREQUENCY.Set(nrf.TWI_FREQUENCY_FREQUENCY_K100)
|
||||
@@ -350,3 +345,41 @@ func (i2c *I2C) readByte() (byte, error) {
|
||||
i2c.Bus.EVENTS_RXDREADY.Set(0)
|
||||
return byte(i2c.Bus.RXD.Get()), nil
|
||||
}
|
||||
|
||||
var rngStarted = false
|
||||
|
||||
// GetRNG returns 32 bits of non-deterministic random data based on internal thermal noise.
|
||||
// According to Nordic's documentation, the random output is suitable for cryptographic purposes.
|
||||
func GetRNG() (ret uint32, err error) {
|
||||
// There's no apparent way to check the status of the RNG peripheral's task, so simply start it
|
||||
// to avoid deadlocking while waiting for output.
|
||||
if !rngStarted {
|
||||
nrf.RNG.TASKS_START.Set(1)
|
||||
nrf.RNG.SetCONFIG_DERCEN(nrf.RNG_CONFIG_DERCEN_Enabled)
|
||||
rngStarted = true
|
||||
}
|
||||
|
||||
// The RNG returns one byte at a time, so stack up four bytes into a single uint32 for return.
|
||||
for i := 0; i < 4; i++ {
|
||||
// Wait for data to be ready.
|
||||
for nrf.RNG.EVENTS_VALRDY.Get() == 0 {
|
||||
}
|
||||
// Append random byte to output.
|
||||
ret = (ret << 8) ^ nrf.RNG.GetVALUE()
|
||||
// Unset the EVENTS_VALRDY register to avoid reading the same random output twice.
|
||||
nrf.RNG.EVENTS_VALRDY.Set(0)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// ReadTemperature reads the silicon die temperature of the chip. The return
|
||||
// value is in milli-celsius.
|
||||
func ReadTemperature() int32 {
|
||||
nrf.TEMP.TASKS_START.Set(1)
|
||||
for nrf.TEMP.EVENTS_DATARDY.Get() == 0 {
|
||||
}
|
||||
temp := int32(nrf.TEMP.TEMP.Get()) * 250 // the returned value is in units of 0.25°C
|
||||
nrf.TEMP.EVENTS_DATARDY.Set(0)
|
||||
return temp
|
||||
}
|
||||
|
||||
@@ -9,16 +9,16 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
DFU_MAGIC_SERIAL_ONLY_RESET = 0x4e
|
||||
DFU_MAGIC_UF2_RESET = 0x57
|
||||
DFU_MAGIC_OTA_RESET = 0xA8
|
||||
dfuMagicSerialOnlyReset = 0x4e
|
||||
dfuMagicUF2Reset = 0x57
|
||||
dfuMagicOTAReset = 0xA8
|
||||
)
|
||||
|
||||
// EnterSerialBootloader resets the chip into the serial bootloader. After
|
||||
// reset, it can be flashed using serial/nrfutil.
|
||||
func EnterSerialBootloader() {
|
||||
arm.DisableInterrupts()
|
||||
nrf.POWER.GPREGRET.Set(DFU_MAGIC_SERIAL_ONLY_RESET)
|
||||
nrf.POWER.GPREGRET.Set(dfuMagicSerialOnlyReset)
|
||||
arm.SystemReset()
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func EnterSerialBootloader() {
|
||||
// can be flashed via nrfutil or by copying a UF2 file to the mass storage device
|
||||
func EnterUF2Bootloader() {
|
||||
arm.DisableInterrupts()
|
||||
nrf.POWER.GPREGRET.Set(DFU_MAGIC_UF2_RESET)
|
||||
nrf.POWER.GPREGRET.Set(dfuMagicUF2Reset)
|
||||
arm.SystemReset()
|
||||
}
|
||||
|
||||
@@ -34,6 +34,6 @@ func EnterUF2Bootloader() {
|
||||
// flashed via an OTA update
|
||||
func EnterOTABootloader() {
|
||||
arm.DisableInterrupts()
|
||||
nrf.POWER.GPREGRET.Set(DFU_MAGIC_OTA_RESET)
|
||||
nrf.POWER.GPREGRET.Set(dfuMagicOTAReset)
|
||||
arm.SystemReset()
|
||||
}
|
||||
|
||||
@@ -42,13 +42,19 @@ const deviceName = nxp.Device
|
||||
|
||||
const (
|
||||
PinInput PinMode = iota
|
||||
PinInputPullUp
|
||||
PinInputPullDown
|
||||
PinInputPullup
|
||||
PinInputPulldown
|
||||
PinOutput
|
||||
PinOutputOpenDrain
|
||||
PinDisable
|
||||
)
|
||||
|
||||
// Deprecated: use PinInputPullup and PinInputPulldown instead.
|
||||
const (
|
||||
PinInputPullUp = PinInputPullup
|
||||
PinInputPullDown = PinInputPulldown
|
||||
)
|
||||
|
||||
const (
|
||||
PA00 Pin = iota
|
||||
PA01
|
||||
@@ -223,11 +229,11 @@ func (p Pin) Configure(config PinConfig) {
|
||||
gpio.PDDR.ClearBits(1 << pos)
|
||||
pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos))
|
||||
|
||||
case PinInputPullUp:
|
||||
case PinInputPullup:
|
||||
gpio.PDDR.ClearBits(1 << pos)
|
||||
pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos) | nxp.PORT_PCR0_PE | nxp.PORT_PCR0_PS)
|
||||
|
||||
case PinInputPullDown:
|
||||
case PinInputPulldown:
|
||||
gpio.PDDR.ClearBits(1 << pos)
|
||||
pcr.Set((1 << nxp.PORT_PCR0_MUX_Pos) | nxp.PORT_PCR0_PE)
|
||||
|
||||
|
||||
@@ -203,8 +203,8 @@ func (u *UART) Disable() {
|
||||
u.C2.Set(0)
|
||||
|
||||
// reconfigure pin
|
||||
u.DefaultRX.Configure(PinConfig{Mode: PinInputPullUp})
|
||||
u.DefaultTX.Configure(PinConfig{Mode: PinInputPullUp})
|
||||
u.DefaultRX.Configure(PinConfig{Mode: PinInputPullup})
|
||||
u.DefaultTX.Configure(PinConfig{Mode: PinInputPullup})
|
||||
|
||||
// clear flags
|
||||
u.S1.Get()
|
||||
|
||||
@@ -11,36 +11,36 @@ const deviceName = rp.Device
|
||||
|
||||
const (
|
||||
// GPIO pins
|
||||
GPIO0 Pin = 0
|
||||
GPIO1 Pin = 1
|
||||
GPIO2 Pin = 2
|
||||
GPIO3 Pin = 3
|
||||
GPIO4 Pin = 4
|
||||
GPIO5 Pin = 5
|
||||
GPIO6 Pin = 6
|
||||
GPIO7 Pin = 7
|
||||
GPIO8 Pin = 8
|
||||
GPIO9 Pin = 9
|
||||
GPIO10 Pin = 10
|
||||
GPIO11 Pin = 11
|
||||
GPIO12 Pin = 12
|
||||
GPIO13 Pin = 13
|
||||
GPIO14 Pin = 14
|
||||
GPIO15 Pin = 15
|
||||
GPIO16 Pin = 16
|
||||
GPIO17 Pin = 17
|
||||
GPIO18 Pin = 18
|
||||
GPIO19 Pin = 19
|
||||
GPIO20 Pin = 20
|
||||
GPIO21 Pin = 21
|
||||
GPIO22 Pin = 22
|
||||
GPIO23 Pin = 23
|
||||
GPIO24 Pin = 24
|
||||
GPIO25 Pin = 25
|
||||
GPIO26 Pin = 26
|
||||
GPIO27 Pin = 27
|
||||
GPIO28 Pin = 28
|
||||
GPIO29 Pin = 29
|
||||
GPIO0 Pin = 0 // peripherals: PWM0 channel A
|
||||
GPIO1 Pin = 1 // peripherals: PWM0 channel B
|
||||
GPIO2 Pin = 2 // peripherals: PWM1 channel A
|
||||
GPIO3 Pin = 3 // peripherals: PWM1 channel B
|
||||
GPIO4 Pin = 4 // peripherals: PWM2 channel A
|
||||
GPIO5 Pin = 5 // peripherals: PWM2 channel B
|
||||
GPIO6 Pin = 6 // peripherals: PWM3 channel A
|
||||
GPIO7 Pin = 7 // peripherals: PWM3 channel B
|
||||
GPIO8 Pin = 8 // peripherals: PWM4 channel A
|
||||
GPIO9 Pin = 9 // peripherals: PWM4 channel B
|
||||
GPIO10 Pin = 10 // peripherals: PWM5 channel A
|
||||
GPIO11 Pin = 11 // peripherals: PWM5 channel B
|
||||
GPIO12 Pin = 12 // peripherals: PWM6 channel A
|
||||
GPIO13 Pin = 13 // peripherals: PWM6 channel B
|
||||
GPIO14 Pin = 14 // peripherals: PWM7 channel A
|
||||
GPIO15 Pin = 15 // peripherals: PWM7 channel B
|
||||
GPIO16 Pin = 16 // peripherals: PWM0 channel A
|
||||
GPIO17 Pin = 17 // peripherals: PWM0 channel B
|
||||
GPIO18 Pin = 18 // peripherals: PWM1 channel A
|
||||
GPIO19 Pin = 19 // peripherals: PWM1 channel B
|
||||
GPIO20 Pin = 20 // peripherals: PWM2 channel A
|
||||
GPIO21 Pin = 21 // peripherals: PWM2 channel B
|
||||
GPIO22 Pin = 22 // peripherals: PWM3 channel A
|
||||
GPIO23 Pin = 23 // peripherals: PWM3 channel B
|
||||
GPIO24 Pin = 24 // peripherals: PWM4 channel A
|
||||
GPIO25 Pin = 25 // peripherals: PWM4 channel B
|
||||
GPIO26 Pin = 26 // peripherals: PWM5 channel A
|
||||
GPIO27 Pin = 27 // peripherals: PWM5 channel B
|
||||
GPIO28 Pin = 28 // peripherals: PWM6 channel A
|
||||
GPIO29 Pin = 29 // peripherals: PWM6 channel B
|
||||
|
||||
// Analog pins
|
||||
ADC0 Pin = GPIO26
|
||||
|
||||
@@ -17,8 +17,8 @@ const (
|
||||
adc0_CH ADCChannel = iota
|
||||
adc1_CH
|
||||
adc2_CH
|
||||
adc3_CH // Note: GPIO29 not broken out on pico board
|
||||
ADC_TEMP_SENSOR // Internal temperature sensor channel
|
||||
adc3_CH // Note: GPIO29 not broken out on pico board
|
||||
adcTempSensor // Internal temperature sensor channel
|
||||
)
|
||||
|
||||
// Used to serialise ADC sampling
|
||||
@@ -75,19 +75,17 @@ func (a ADC) GetADCChannel() (c ADCChannel, err error) {
|
||||
return c, err
|
||||
}
|
||||
|
||||
// Configure sets the channel's associated pin to analog input mode or powers on the temperature sensor for ADC_TEMP_SENSOR.
|
||||
// Configure sets the channel's associated pin to analog input mode.
|
||||
// The powered on temperature sensor increases ADC_AVDD current by approximately 40 μA.
|
||||
func (c ADCChannel) Configure(config ADCConfig) error {
|
||||
if config.Reference != 0 {
|
||||
adcAref = config.Reference
|
||||
}
|
||||
if p, err := c.Pin(); err == nil {
|
||||
p.Configure(PinConfig{Mode: PinAnalog})
|
||||
}
|
||||
if c == ADC_TEMP_SENSOR {
|
||||
// Enable temperature sensor bias source
|
||||
rp.ADC.CS.SetBits(rp.ADC_CS_TS_EN)
|
||||
p, err := c.Pin()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p.Configure(PinConfig{Mode: PinAnalog})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -112,13 +110,16 @@ func (c ADCChannel) getVoltage() uint32 {
|
||||
}
|
||||
|
||||
// ReadTemperature does a one-shot sample of the internal temperature sensor and returns a milli-celsius reading.
|
||||
// Only works on the ADC_TEMP_SENSOR channel. aka AINSEL=4. Other channels will return 0
|
||||
func (c ADCChannel) ReadTemperature() (millicelsius uint32) {
|
||||
if c != ADC_TEMP_SENSOR {
|
||||
return
|
||||
func ReadTemperature() (millicelsius int32) {
|
||||
if rp.ADC.CS.Get()&rp.ADC_CS_EN == 0 {
|
||||
InitADC()
|
||||
}
|
||||
|
||||
// Enable temperature sensor bias source
|
||||
rp.ADC.CS.SetBits(rp.ADC_CS_TS_EN)
|
||||
|
||||
// T = 27 - (ADC_voltage - 0.706)/0.001721
|
||||
return (27000<<16 - (c.getVoltage()-706<<16)*581) >> 16
|
||||
return (27000<<16 - (int32(adcTempSensor.getVoltage())-706<<16)*581) >> 16
|
||||
}
|
||||
|
||||
// waitForReady spins waiting for the ADC peripheral to become ready.
|
||||
|
||||
@@ -10,11 +10,6 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
KHz = 1000
|
||||
MHz = 1000000
|
||||
)
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 125 * MHz
|
||||
}
|
||||
|
||||
@@ -226,12 +226,8 @@ type PinChange uint8
|
||||
|
||||
// Pin change interrupt constants for SetInterrupt.
|
||||
const (
|
||||
// PinLevelLow triggers whenever pin is at a low (around 0V) logic level.
|
||||
PinLevelLow PinChange = 1 << iota
|
||||
// PinLevelLow triggers whenever pin is at a high (around 3V) logic level.
|
||||
PinLevelHigh
|
||||
// Edge falling
|
||||
PinFalling
|
||||
PinFalling PinChange = 4 << iota
|
||||
// Edge rising
|
||||
PinRising
|
||||
)
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
//go:build rp2040
|
||||
// +build rp2040
|
||||
|
||||
// Implementation based on code located here:
|
||||
// https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_lwip/random.c
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
)
|
||||
|
||||
const numberOfCycles = 32
|
||||
|
||||
// GetRNG returns 32 bits of semi-random data based on ring oscillator.
|
||||
//
|
||||
// Unlike some other implementations of GetRNG, these random numbers are not
|
||||
// cryptographically secure and must not be used for cryptographic operations
|
||||
// (nonces, etc).
|
||||
func GetRNG() (uint32, error) {
|
||||
var val uint32
|
||||
for i := 0; i < 4; i++ {
|
||||
val = (val << 8) | uint32(roscRandByte())
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
var randomByte uint8
|
||||
|
||||
func roscRandByte() uint8 {
|
||||
var poly uint8
|
||||
for i := 0; i < numberOfCycles; i++ {
|
||||
if randomByte&0x80 != 0 {
|
||||
poly = 0x35
|
||||
} else {
|
||||
poly = 0
|
||||
}
|
||||
randomByte = ((randomByte << 1) | uint8(rp.ROSC.GetRANDOMBIT()) ^ poly)
|
||||
// TODO: delay a little because the random bit is a little slow
|
||||
}
|
||||
return randomByte
|
||||
}
|
||||
@@ -38,10 +38,9 @@ type SPIConfig struct {
|
||||
}
|
||||
|
||||
var (
|
||||
ErrLSBNotSupported = errors.New("SPI LSB unsupported on PL022")
|
||||
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
|
||||
ErrSPITimeout = errors.New("SPI timeout")
|
||||
ErrSPIBaud = errors.New("SPI baud too low or above 66.5Mhz")
|
||||
ErrLSBNotSupported = errors.New("SPI LSB unsupported on PL022")
|
||||
ErrSPITimeout = errors.New("SPI timeout")
|
||||
ErrSPIBaud = errors.New("SPI baud too low or above 66.5Mhz")
|
||||
)
|
||||
|
||||
type SPI struct {
|
||||
|
||||
@@ -137,7 +137,7 @@ func (i2c *I2C) Configure(config I2CConfig) error {
|
||||
|
||||
// default to 100 kHz (Sm, standard mode) if no frequency is set
|
||||
if config.Frequency == 0 {
|
||||
config.Frequency = TWI_FREQ_100KHZ
|
||||
config.Frequency = 100 * KHz
|
||||
}
|
||||
|
||||
// configure I2C input clock
|
||||
|
||||
+2
-57
@@ -1,5 +1,5 @@
|
||||
//go:build !baremetal || (stm32 && !stm32f7x2 && !stm32l5x2) || fe310 || k210 || (nxp && !mk66f18) || atmega
|
||||
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2 fe310 k210 nxp,!mk66f18 atmega
|
||||
//go:build !baremetal || atmega || esp32 || fe310 || k210 || nrf || (nxp && !mk66f18) || rp2040 || sam || (stm32 && !stm32f7x2 && !stm32l5x2)
|
||||
// +build !baremetal atmega esp32 fe310 k210 nrf nxp,!mk66f18 rp2040 sam stm32,!stm32f7x2,!stm32l5x2
|
||||
|
||||
package machine
|
||||
|
||||
@@ -17,58 +17,3 @@ var (
|
||||
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
|
||||
errSPIInvalidMachineConfig = errors.New("SPI port was not configured properly by the machine")
|
||||
)
|
||||
|
||||
// Tx handles read/write operation for SPI interface. Since SPI is a syncronous write/read
|
||||
// interface, there must always be the same number of bytes written as bytes read.
|
||||
// The Tx method knows about this, and offers a few different ways of calling it.
|
||||
//
|
||||
// This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer.
|
||||
// Note that the tx and rx buffers must be the same size:
|
||||
//
|
||||
// spi.Tx(tx, rx)
|
||||
//
|
||||
// This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros
|
||||
// until all the bytes in the command packet have been received:
|
||||
//
|
||||
// spi.Tx(tx, nil)
|
||||
//
|
||||
// This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet":
|
||||
//
|
||||
// spi.Tx(nil, rx)
|
||||
func (spi SPI) Tx(w, r []byte) error {
|
||||
var err error
|
||||
|
||||
switch {
|
||||
case w == nil:
|
||||
// read only, so write zero and read a result.
|
||||
for i := range r {
|
||||
r[i], err = spi.Transfer(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case r == nil:
|
||||
// write only
|
||||
for _, b := range w {
|
||||
_, err = spi.Transfer(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
// write/read
|
||||
if len(w) != len(r) {
|
||||
return ErrTxInvalidSliceSize
|
||||
}
|
||||
|
||||
for i, b := range w {
|
||||
r[i], err = spi.Transfer(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
//go:build !baremetal || atmega || fe310 || k210 || (nxp && !mk66f18) || (stm32 && !stm32f7x2 && !stm32l5x2)
|
||||
// +build !baremetal atmega fe310 k210 nxp,!mk66f18 stm32,!stm32f7x2,!stm32l5x2
|
||||
|
||||
// This file implements the SPI Tx function for targets that don't have a custom
|
||||
// (faster) implementation for it.
|
||||
|
||||
package machine
|
||||
|
||||
// Tx handles read/write operation for SPI interface. Since SPI is a syncronous write/read
|
||||
// interface, there must always be the same number of bytes written as bytes read.
|
||||
// The Tx method knows about this, and offers a few different ways of calling it.
|
||||
//
|
||||
// This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer.
|
||||
// Note that the tx and rx buffers must be the same size:
|
||||
//
|
||||
// spi.Tx(tx, rx)
|
||||
//
|
||||
// This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros
|
||||
// until all the bytes in the command packet have been received:
|
||||
//
|
||||
// spi.Tx(tx, nil)
|
||||
//
|
||||
// This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet":
|
||||
//
|
||||
// spi.Tx(nil, rx)
|
||||
func (spi SPI) Tx(w, r []byte) error {
|
||||
var err error
|
||||
|
||||
switch {
|
||||
case w == nil:
|
||||
// read only, so write zero and read a result.
|
||||
for i := range r {
|
||||
r[i], err = spi.Transfer(0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case r == nil:
|
||||
// write only
|
||||
for _, b := range w {
|
||||
_, err = spi.Transfer(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
// write/read
|
||||
if len(w) != len(r) {
|
||||
return ErrTxInvalidSliceSize
|
||||
}
|
||||
|
||||
for i, b := range w {
|
||||
r[i], err = spi.Transfer(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
+4
-4
@@ -8,20 +8,20 @@ import "errors"
|
||||
var errUARTBufferEmpty = errors.New("UART buffer empty")
|
||||
|
||||
// UARTParity is the parity setting to be used for UART communication.
|
||||
type UARTParity int
|
||||
type UARTParity uint8
|
||||
|
||||
const (
|
||||
// ParityNone means to not use any parity checking. This is
|
||||
// the most common setting.
|
||||
ParityNone UARTParity = 0
|
||||
ParityNone UARTParity = iota
|
||||
|
||||
// ParityEven means to expect that the total number of 1 bits sent
|
||||
// should be an even number.
|
||||
ParityEven UARTParity = 1
|
||||
ParityEven
|
||||
|
||||
// ParityOdd means to expect that the total number of 1 bits sent
|
||||
// should be an odd number.
|
||||
ParityOdd UARTParity = 2
|
||||
ParityOdd
|
||||
)
|
||||
|
||||
// To implement the UART interface for a board, you must declare a concrete type as follows:
|
||||
|
||||
@@ -20,21 +20,46 @@ var heapStartSymbol [0]byte
|
||||
//go:extern __global_base
|
||||
var globalsStartSymbol [0]byte
|
||||
|
||||
const (
|
||||
// wasmMemoryIndex is always zero until the multi-memory feature is used.
|
||||
//
|
||||
// See https://github.com/WebAssembly/multi-memory
|
||||
wasmMemoryIndex = 0
|
||||
|
||||
// wasmPageSize is the size of a page in WebAssembly's 32-bit memory. This
|
||||
// is also its only unit of change.
|
||||
//
|
||||
// See https://www.w3.org/TR/wasm-core-1/#page-size
|
||||
wasmPageSize = 64 * 1024
|
||||
)
|
||||
|
||||
// wasm_memory_size invokes the "memory.size" instruction, which returns the
|
||||
// current size to the memory at the given index (always wasmMemoryIndex), in
|
||||
// pages.
|
||||
//
|
||||
//export llvm.wasm.memory.size.i32
|
||||
func wasm_memory_size(index int32) int32
|
||||
|
||||
// wasm_memory_grow invokes the "memory.grow" instruction, which attempts to
|
||||
// increase the size of the memory at the given index (always wasmMemoryIndex),
|
||||
// by the delta (in pages). This returns the previous size on success of -1 on
|
||||
// failure.
|
||||
//
|
||||
//export llvm.wasm.memory.grow.i32
|
||||
func wasm_memory_grow(index int32, delta int32) int32
|
||||
|
||||
var (
|
||||
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
|
||||
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
|
||||
// heapStart is the current memory offset which starts the heap. The heap
|
||||
// extends from this offset until heapEnd (exclusive).
|
||||
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
|
||||
|
||||
// heapEnd is the current memory length in bytes.
|
||||
heapEnd = uintptr(wasm_memory_size(wasmMemoryIndex) * wasmPageSize)
|
||||
|
||||
globalsStart = uintptr(unsafe.Pointer(&globalsStartSymbol))
|
||||
globalsEnd = uintptr(unsafe.Pointer(&heapStartSymbol))
|
||||
)
|
||||
|
||||
const wasmPageSize = 64 * 1024
|
||||
|
||||
func align(ptr uintptr) uintptr {
|
||||
// Align to 16, which is the alignment of max_align_t:
|
||||
// https://godbolt.org/z/dYqTsWrGq
|
||||
@@ -48,44 +73,67 @@ func getCurrentStackPointer() uintptr
|
||||
// otherwise.
|
||||
func growHeap() bool {
|
||||
// Grow memory by the available size, which means the heap size is doubled.
|
||||
memorySize := wasm_memory_size(0)
|
||||
result := wasm_memory_grow(0, memorySize)
|
||||
memorySize := wasm_memory_size(wasmMemoryIndex)
|
||||
result := wasm_memory_grow(wasmMemoryIndex, memorySize)
|
||||
if result == -1 {
|
||||
// Grow failed.
|
||||
return false
|
||||
}
|
||||
|
||||
setHeapEnd(uintptr(wasm_memory_size(0) * wasmPageSize))
|
||||
setHeapEnd(uintptr(wasm_memory_size(wasmMemoryIndex) * wasmPageSize))
|
||||
|
||||
// Heap has grown successfully.
|
||||
return true
|
||||
}
|
||||
|
||||
// The below functions override the default allocator of wasi-libc.
|
||||
// Most functions are defined but unimplemented to make sure that if there is
|
||||
// any code using them, they will get an error instead of (incorrectly) using
|
||||
// the wasi-libc dlmalloc heap implementation instead. If they are needed by any
|
||||
// program, they can certainly be implemented.
|
||||
// The below functions override the default allocator of wasi-libc. This ensures
|
||||
// code linked from other languages can allocate memory without colliding with
|
||||
// our GC allocations.
|
||||
|
||||
var allocs = make(map[uintptr][]byte)
|
||||
|
||||
//export malloc
|
||||
func libc_malloc(size uintptr) unsafe.Pointer {
|
||||
return alloc(size, nil)
|
||||
buf := make([]byte, size)
|
||||
ptr := unsafe.Pointer(&buf[0])
|
||||
allocs[uintptr(ptr)] = buf
|
||||
return ptr
|
||||
}
|
||||
|
||||
//export free
|
||||
func libc_free(ptr unsafe.Pointer) {
|
||||
free(ptr)
|
||||
if ptr == nil {
|
||||
return
|
||||
}
|
||||
if _, ok := allocs[uintptr(ptr)]; ok {
|
||||
delete(allocs, uintptr(ptr))
|
||||
} else {
|
||||
panic("free: invalid pointer")
|
||||
}
|
||||
}
|
||||
|
||||
//export calloc
|
||||
func libc_calloc(nmemb, size uintptr) unsafe.Pointer {
|
||||
// Note: we could be even more correct here and check that nmemb * size
|
||||
// doesn't overflow. However the current implementation should normally work
|
||||
// fine.
|
||||
return alloc(nmemb*size, nil)
|
||||
// No difference between calloc and malloc.
|
||||
return libc_malloc(nmemb * size)
|
||||
}
|
||||
|
||||
//export realloc
|
||||
func libc_realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer {
|
||||
return realloc(ptr, size)
|
||||
func libc_realloc(oldPtr unsafe.Pointer, size uintptr) unsafe.Pointer {
|
||||
// It's hard to optimize this to expand the current buffer with our GC, but
|
||||
// it is theoretically possible. For now, just always allocate fresh.
|
||||
buf := make([]byte, size)
|
||||
|
||||
if oldPtr != nil {
|
||||
if oldBuf, ok := allocs[uintptr(oldPtr)]; ok {
|
||||
copy(buf, oldBuf)
|
||||
delete(allocs, uintptr(oldPtr))
|
||||
} else {
|
||||
panic("realloc: invalid pointer")
|
||||
}
|
||||
}
|
||||
|
||||
ptr := unsafe.Pointer(&buf[0])
|
||||
allocs[uintptr(ptr)] = buf
|
||||
return ptr
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build runtime_asserts
|
||||
|
||||
package runtime
|
||||
|
||||
// enable assertions for the garbage collector
|
||||
const gcAsserts = true
|
||||
|
||||
// enable asserts for the scheduler
|
||||
const schedulerAsserts = true
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build !runtime_asserts
|
||||
|
||||
package runtime
|
||||
|
||||
// disable assertions for the garbage collector
|
||||
const gcAsserts = false
|
||||
|
||||
// disable assertions for the scheduler
|
||||
const schedulerAsserts = false
|
||||
@@ -25,7 +25,9 @@ package runtime
|
||||
// heapStart..metadataStart.
|
||||
//
|
||||
// More information:
|
||||
// https://aykevl.nl/2020/09/gc-tinygo
|
||||
// https://github.com/micropython/micropython/wiki/Memory-Manager
|
||||
// https://github.com/micropython/micropython/blob/master/py/gc.c
|
||||
// "The Garbage Collection Handbook" by Richard Jones, Antony Hosking, Eliot
|
||||
// Moss.
|
||||
|
||||
@@ -35,11 +37,7 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Set gcDebug to true to print debug information.
|
||||
const (
|
||||
gcDebug = false // print debug info
|
||||
gcAsserts = gcDebug // perform sanity checks
|
||||
)
|
||||
const gcDebug = false
|
||||
|
||||
// Some globals + constants for the entire GC.
|
||||
|
||||
@@ -288,7 +286,14 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
|
||||
// could be found. Run a garbage collection cycle to reclaim
|
||||
// free memory and try again.
|
||||
heapScanCount = 2
|
||||
GC()
|
||||
freeBytes := runGC()
|
||||
heapSize := uintptr(metadataStart) - heapStart
|
||||
if freeBytes < heapSize/3 {
|
||||
// Ensure there is at least 33% headroom.
|
||||
// This percentage was arbitrarily chosen, and may need to
|
||||
// be tuned in the future.
|
||||
growHeap()
|
||||
}
|
||||
} else {
|
||||
// Even after garbage collection, no free memory could be found.
|
||||
// Try to increase heap size.
|
||||
@@ -379,6 +384,13 @@ func free(ptr unsafe.Pointer) {
|
||||
|
||||
// GC performs a garbage collection cycle.
|
||||
func GC() {
|
||||
runGC()
|
||||
}
|
||||
|
||||
// runGC performs a garbage colleciton cycle. It is the internal implementation
|
||||
// of the runtime.GC() function. The difference is that it returns the number of
|
||||
// free bytes in the heap after the GC is finished.
|
||||
func runGC() (freeBytes uintptr) {
|
||||
if gcDebug {
|
||||
println("running collection cycle...")
|
||||
}
|
||||
@@ -420,12 +432,14 @@ func GC() {
|
||||
|
||||
// Sweep phase: free all non-marked objects and unmark marked objects for
|
||||
// the next collection cycle.
|
||||
sweep()
|
||||
freeBytes = sweep()
|
||||
|
||||
// Show how much has been sweeped, for debugging.
|
||||
if gcDebug {
|
||||
dumpHeap()
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// markRoots reads all pointers from start to end (exclusive) and if they look
|
||||
@@ -568,7 +582,8 @@ func markRoot(addr, root uintptr) {
|
||||
}
|
||||
|
||||
// Sweep goes through all memory and frees unmarked memory.
|
||||
func sweep() {
|
||||
// It returns how many bytes are free in the heap after the sweep.
|
||||
func sweep() (freeBytes uintptr) {
|
||||
freeCurrentObject := false
|
||||
for block := gcBlock(0); block < endBlock; block++ {
|
||||
switch block.state() {
|
||||
@@ -577,11 +592,13 @@ func sweep() {
|
||||
block.markFree()
|
||||
freeCurrentObject = true
|
||||
gcFrees++
|
||||
freeBytes += bytesPerBlock
|
||||
case blockStateTail:
|
||||
if freeCurrentObject {
|
||||
// This is a tail object following an unmarked head.
|
||||
// Free it now.
|
||||
block.markFree()
|
||||
freeBytes += bytesPerBlock
|
||||
}
|
||||
case blockStateMark:
|
||||
// This is a marked object. The next tail blocks must not be freed,
|
||||
@@ -589,8 +606,11 @@ func sweep() {
|
||||
// collect this object if it is unreferenced then.
|
||||
block.unmark()
|
||||
freeCurrentObject = false
|
||||
case blockStateFree:
|
||||
freeBytes += bytesPerBlock
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// looksLikePointer returns whether this could be a pointer. Currently, it
|
||||
|
||||
@@ -11,8 +11,6 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const gcAsserts = false // perform sanity checks
|
||||
|
||||
// Ever-incrementing pointer: no memory is freed.
|
||||
var heapptr = heapStart
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const gcAsserts = false // perform sanity checks
|
||||
|
||||
var gcTotalAlloc uint64 // for runtime.MemStats
|
||||
var gcMallocs uint64
|
||||
var gcFrees uint64
|
||||
|
||||
@@ -10,8 +10,7 @@ import (
|
||||
|
||||
var ErrUnimplemented = errors.New("runtime/pprof: unimplemented")
|
||||
|
||||
type Profile struct {
|
||||
}
|
||||
type Profile struct{}
|
||||
|
||||
func StartCPUProfile(w io.Writer) error {
|
||||
return nil
|
||||
@@ -28,6 +27,18 @@ func Lookup(name string) *Profile {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Profile) Name() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *Profile) Count() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (p *Profile) WriteTo(w io.Writer, debug int) error {
|
||||
return ErrUnimplemented
|
||||
}
|
||||
|
||||
func Profiles() []*Profile {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// Stubs for the runtime/trace package
|
||||
package trace
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
func Start(w io.Writer) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func Stop() {}
|
||||
@@ -34,6 +34,17 @@ func (m *Map) LoadOrStore(key, value interface{}) (actual interface{}, loaded bo
|
||||
return value, false
|
||||
}
|
||||
|
||||
func (m *Map) LoadAndDelete(key interface{}) (value interface{}, loaded bool) {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
value, ok := m.m[key]
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
delete(m.m, key)
|
||||
return value, true
|
||||
}
|
||||
|
||||
func (m *Map) Store(key, value interface{}) {
|
||||
m.lock.Lock()
|
||||
defer m.lock.Unlock()
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package sync_test
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMapLoadAndDelete(t *testing.T) {
|
||||
var sm sync.Map
|
||||
sm.Store("present", "value")
|
||||
|
||||
if v, ok := sm.LoadAndDelete("present"); !ok || v != "value" {
|
||||
t.Errorf("LoadAndDelete returned %v, %v, want value, true", v, ok)
|
||||
}
|
||||
|
||||
if v, ok := sm.LoadAndDelete("absent"); ok || v != nil {
|
||||
t.Errorf("LoadAndDelete returned %v, %v, want nil, false", v, ok)
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"inherits": ["nrf52840", "nrf52840-s140v6-uf2"],
|
||||
"build-tags": ["circuitplay_bluefruit"],
|
||||
"serial-port": ["acm:239a:8045", "acm:239a:45"],
|
||||
"serial-port": ["acm:239a:8045"],
|
||||
"msd-volume-name": "CPLAYBTBOOT"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"build-tags": ["circuitplay_express"],
|
||||
"flash-1200-bps-reset": "true",
|
||||
"flash-method": "msd",
|
||||
"serial-port": ["acm:239a:8018", "acm:239a:18"],
|
||||
"serial-port": ["acm:239a:8018"],
|
||||
"msd-volume-name": "CPLAYBOOT",
|
||||
"msd-firmware-name": "firmware.uf2"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"inherits": ["nrf52840", "nrf52840-s140v6-uf2"],
|
||||
"build-tags": ["clue_alpha"],
|
||||
"serial-port": ["acm:239a:8072", "acm:239a:0072", "acm:239a:0071", "acm:239a:8071"],
|
||||
"serial-port": ["acm:239a:8072", "acm:239a:8071"],
|
||||
"msd-volume-name": "CLUEBOOT"
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"inherits": ["esp32c3"],
|
||||
"build-tags": ["esp32c312f", "esp32c3", "esp"]
|
||||
"build-tags": ["esp32c312f"]
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user