mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-09 13:33:39 +00:00
Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dc449882ad | |||
| a158d3194f | |||
| 806498f099 | |||
| e3bc6da9e4 | |||
| 3e2471d934 | |||
| a545f17d2e | |||
| f4375d0452 | |||
| 756cdf44ed | |||
| 9037bf8bf0 | |||
| bfe9ee378f | |||
| 37a4fa205c | |||
| 59cc7d4c42 | |||
| ab64e215dd | |||
| 253dbe335a | |||
| 0ef86e1534 | |||
| 72270f9052 | |||
| 67ec722a74 | |||
| 62294feb56 | |||
| f1e25a18d2 | |||
| a2f886a67a | |||
| f791c821ff | |||
| a93f0ed12a | |||
| c25dd0a972 | |||
| 215dd3f0be | |||
| c51f5cea0b | |||
| 395ee2d338 | |||
| 069e4f0d98 | |||
| d1eb642d45 | |||
| 5f2e72f371 | |||
| 5b581d83b3 | |||
| d845f1e1b2 | |||
| 00d46bd25d | |||
| 01d2ef327d | |||
| 4da1f6bcbe | |||
| 14ddba8519 | |||
| a7b205c26c | |||
| c83f712c17 | |||
| fffad84a63 | |||
| e075e0591d | |||
| 46d2696363 | |||
| e98dfd6c46 | |||
| 9126b95737 | |||
| 3871b831af | |||
| 7755f2385c | |||
| 04601a29e8 | |||
| 9aadea930f | |||
| 6efa94035e | |||
| db8d80755f | |||
| dc91c96305 | |||
| 08b3a4576d | |||
| acba0748f1 | |||
| ef72c5bb4e | |||
| 93cc03b15a | |||
| fdc4bbbfad | |||
| dd4e9e86e7 | |||
| ad32d26511 | |||
| 4619896c19 | |||
| cec237917f | |||
| 4d2a6d2bbe | |||
| 6d5f4c4be2 | |||
| 0cb5d336f4 | |||
| 91ee4d0030 | |||
| 785eb93b62 | |||
| e041a8ed88 | |||
| d01d85930d | |||
| ac821d8295 |
@@ -27,7 +27,7 @@ jobs:
|
|||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.21'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v3
|
||||||
@@ -108,7 +108,7 @@ jobs:
|
|||||||
# We're doing the former here, to keep artifact uploads fast.
|
# We're doing the former here, to keep artifact uploads fast.
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: release-double-zipped
|
name: darwin-amd64-double-zipped
|
||||||
path: build/tinygo.darwin-amd64.tar.gz
|
path: build/tinygo.darwin-amd64.tar.gz
|
||||||
- name: Smoke tests
|
- name: Smoke tests
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -126,7 +126,7 @@ jobs:
|
|||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.21'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Build TinyGo
|
- name: Build TinyGo
|
||||||
run: go install
|
run: go install
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ jobs:
|
|||||||
# statically linked binary.
|
# statically linked binary.
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: golang:1.20-alpine
|
image: golang:1.21-alpine
|
||||||
steps:
|
steps:
|
||||||
- name: Install apk dependencies
|
- name: Install apk dependencies
|
||||||
# tar: needed for actions/cache@v3
|
# tar: needed for actions/cache@v3
|
||||||
@@ -135,7 +135,7 @@ jobs:
|
|||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.21'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Install wasmtime
|
- name: Install wasmtime
|
||||||
run: |
|
run: |
|
||||||
@@ -153,6 +153,7 @@ jobs:
|
|||||||
tar -C ~/lib -xf tinygo.linux-amd64.tar.gz
|
tar -C ~/lib -xf tinygo.linux-amd64.tar.gz
|
||||||
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
|
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
|
||||||
- run: make tinygo-test-wasi-fast
|
- run: make tinygo-test-wasi-fast
|
||||||
|
- run: make tinygo-test-wasip1-fast
|
||||||
- run: make smoketest
|
- run: make smoketest
|
||||||
assert-test-linux:
|
assert-test-linux:
|
||||||
# Run all tests that can run on Linux, with LLVM assertions enabled to catch
|
# Run all tests that can run on Linux, with LLVM assertions enabled to catch
|
||||||
@@ -177,12 +178,12 @@ jobs:
|
|||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.21'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: '14'
|
node-version: '16'
|
||||||
- name: Install wasmtime
|
- name: Install wasmtime
|
||||||
run: |
|
run: |
|
||||||
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
|
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
|
||||||
@@ -290,7 +291,7 @@ jobs:
|
|||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.21'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v3
|
||||||
@@ -407,7 +408,7 @@ jobs:
|
|||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.21'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v3
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ jobs:
|
|||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.21'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore cached LLVM source
|
- name: Restore cached LLVM source
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v3
|
||||||
@@ -118,7 +118,7 @@ jobs:
|
|||||||
# We're doing the former here, to keep artifact uploads fast.
|
# We're doing the former here, to keep artifact uploads fast.
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: release-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/release/release.zip
|
path: build/release/release.zip
|
||||||
|
|
||||||
smoke-test-windows:
|
smoke-test-windows:
|
||||||
@@ -143,12 +143,12 @@ jobs:
|
|||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.21'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: release-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/
|
path: build/
|
||||||
- name: Unzip TinyGo build
|
- name: Unzip TinyGo build
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -173,12 +173,12 @@ jobs:
|
|||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.21'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: release-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/
|
path: build/
|
||||||
- name: Unzip TinyGo build
|
- name: Unzip TinyGo build
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -209,12 +209,12 @@ jobs:
|
|||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.20'
|
go-version: '1.21'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: release-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/
|
path: build/
|
||||||
- name: Unzip TinyGo build
|
- name: Unzip TinyGo build
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
@@ -31,3 +31,6 @@
|
|||||||
[submodule "lib/macos-minimal-sdk"]
|
[submodule "lib/macos-minimal-sdk"]
|
||||||
path = lib/macos-minimal-sdk
|
path = lib/macos-minimal-sdk
|
||||||
url = https://github.com/aykevl/macos-minimal-sdk.git
|
url = https://github.com/aykevl/macos-minimal-sdk.git
|
||||||
|
[submodule "lib/renesas-svd"]
|
||||||
|
path = lib/renesas-svd
|
||||||
|
url = https://github.com/tinygo-org/renesas-svd.git
|
||||||
|
|||||||
@@ -1,3 +1,74 @@
|
|||||||
|
0.29.0
|
||||||
|
---
|
||||||
|
|
||||||
|
* **general**
|
||||||
|
- Go 1.21 support
|
||||||
|
- use https for renesas submodule #3856
|
||||||
|
- ci: rename release-double-zipped to something more useful
|
||||||
|
- ci: update Node.js from version 14 to version 16
|
||||||
|
- ci: switch GH actions builds to use Go 1.21 final release
|
||||||
|
- docker: update clang to version 15
|
||||||
|
- docker: use Go 1.21 for Docker dev container build
|
||||||
|
- `main`: add target JSON file in `tinygo info` output
|
||||||
|
- `main`: improve detection of filesystems
|
||||||
|
- `main`: use `go env` instead of doing all detection manually
|
||||||
|
- make: add make task to generate Renesas device wrappers
|
||||||
|
- make: add task to check NodeJS version before running tests
|
||||||
|
- add submodule for Renesas SVD file mirror repo
|
||||||
|
- update to go-serial package v1.6.0
|
||||||
|
- `testing`: add Testing function
|
||||||
|
- `tools/gen-device-svd`: small changes needed for Renesas MCUs
|
||||||
|
* **compiler**
|
||||||
|
- `builder`: update message for max supported Go version
|
||||||
|
- `compiler,reflect`: NumMethods reports exported methods only
|
||||||
|
- `compiler`: add compiler-rt and wasm symbols to table
|
||||||
|
- `compiler`: add compiler-rt to wasm.json
|
||||||
|
- `compiler`: add min and max builtin support
|
||||||
|
- `compiler`: implement clear builtin for maps
|
||||||
|
- `compiler`: implement clear builtin for slices
|
||||||
|
- `compiler`: improve panic message when a runtime call is unavailable
|
||||||
|
- `compiler`: update .ll test output
|
||||||
|
- `loader`: merge go.env file which is now required starting in Go 1.21 to correctly get required packages
|
||||||
|
* **standard library**
|
||||||
|
- `os`: define ErrNoDeadline
|
||||||
|
- `reflect`: Add FieldByNameFunc
|
||||||
|
- `reflect`: add SetZero
|
||||||
|
- `reflect`: fix iterating over maps with interface{} keys
|
||||||
|
- `reflect`: implement Value.Grow
|
||||||
|
- `reflect`: remove unecessary heap allocations
|
||||||
|
- `reflect`: use .key() instead of a type assert
|
||||||
|
- `sync`: add implementation from upstream Go for OnceFunc, OnceValue, and OnceValues
|
||||||
|
* **targets**
|
||||||
|
- `machine`: UART refactor (#3832)
|
||||||
|
- `machine/avr`: pin change interrupt
|
||||||
|
- `machine/macropad_rp2040`: add machine.BUTTON
|
||||||
|
- `machine/nrf`: add I2C timeout
|
||||||
|
- `machine/nrf`: wait for stop condition after reading from the I2C bus
|
||||||
|
- `machine/nRF52`: set SPI TX/RX lengths even data is empty. Fixes #3868 (#3877)
|
||||||
|
- `machine/rp2040`: add missing suffix to CMD_READ_STATUS
|
||||||
|
- `machine/rp2040`: add NoPin support
|
||||||
|
- `machine/rp2040`: move flash related functions into separate file from C imports for correct - LSP. Fixes #3852
|
||||||
|
- `machine/rp2040`: wait for 1000 us after flash reset to avoid issues with busy USB bus
|
||||||
|
- `machine/samd51,rp2040,nrf528xx,stm32`: implement watchdog
|
||||||
|
- `machine/samd51`: fix i2cTimeout was decreasing due to cache activation
|
||||||
|
- `machine/usb`: Add support for HID Keyboard LEDs
|
||||||
|
- `machine/usb`: allow USB Endpoint settings to be changed externally
|
||||||
|
- `machine/usb`: refactor endpoint configuration
|
||||||
|
- `machine/usb`: remove usbDescriptorConfig
|
||||||
|
- `machine/usb/hid,joystick`: fix hidreport (3) (#3802)
|
||||||
|
- `machine/usb/hid`: add RxHandler interface
|
||||||
|
- `machine/usb/hid`: rename Handler() to TxHandler()
|
||||||
|
- `wasi`: allow zero inodes when reading directories
|
||||||
|
- `wasm`: add support for GOOS=wasip1
|
||||||
|
- `wasm`: fix functions exported through //export
|
||||||
|
- `wasm`: remove i64 workaround, use BigInt instead
|
||||||
|
- `example`: adjust time offset
|
||||||
|
- `example`: simplify pininterrupt
|
||||||
|
* **boards**
|
||||||
|
- `targets`: add AKIZUKI DENSHI AE-RP2040
|
||||||
|
- `targets`: adding new uf2 target for PCA10056 (#3765)
|
||||||
|
|
||||||
|
|
||||||
0.28.0
|
0.28.0
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,8 +1,8 @@
|
|||||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||||
FROM golang:1.20 AS tinygo-llvm
|
FROM golang:1.21 AS tinygo-llvm
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y apt-utils make cmake clang-11 ninja-build
|
apt-get install -y apt-utils make cmake clang-15 ninja-build
|
||||||
|
|
||||||
COPY ./Makefile /tinygo/Makefile
|
COPY ./Makefile /tinygo/Makefile
|
||||||
|
|
||||||
|
|||||||
@@ -232,6 +232,10 @@ gen-device-rp: build/gen-device-svd
|
|||||||
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/RaspberryPi lib/cmsis-svd/data/RaspberryPi/ src/device/rp/
|
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/RaspberryPi lib/cmsis-svd/data/RaspberryPi/ src/device/rp/
|
||||||
GO111MODULE=off $(GO) fmt ./src/device/rp
|
GO111MODULE=off $(GO) fmt ./src/device/rp
|
||||||
|
|
||||||
|
gen-device-renesas: build/gen-device-svd
|
||||||
|
./build/gen-device-svd -source=https://github.com/tinygo-org/renesas-svd lib/renesas-svd/ src/device/renesas/
|
||||||
|
GO111MODULE=off $(GO) fmt ./src/device/renesas
|
||||||
|
|
||||||
# Get LLVM sources.
|
# Get LLVM sources.
|
||||||
$(LLVM_PROJECTDIR)/llvm:
|
$(LLVM_PROJECTDIR)/llvm:
|
||||||
git clone -b xtensa_release_15.x --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
|
git clone -b xtensa_release_15.x --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
|
||||||
@@ -263,12 +267,22 @@ lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
|
|||||||
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
|
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
|
||||||
cd lib/wasi-libc && make -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC=$(CLANG) AR=$(LLVM_AR) NM=$(LLVM_NM)
|
cd lib/wasi-libc && make -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC=$(CLANG) AR=$(LLVM_AR) NM=$(LLVM_NM)
|
||||||
|
|
||||||
|
# Check for Node.js used during WASM tests.
|
||||||
|
NODEJS_VERSION := $(word 1,$(subst ., ,$(shell node -v | cut -c 2-)))
|
||||||
|
MIN_NODEJS_VERSION=16
|
||||||
|
|
||||||
|
.PHONY: check-nodejs-version
|
||||||
|
check-nodejs-version:
|
||||||
|
ifeq (, $(shell which node))
|
||||||
|
@echo "Install NodeJS version 16+ to run tests."; exit 1;
|
||||||
|
endif
|
||||||
|
@if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 16+ to run tests."; exit 1; fi
|
||||||
|
|
||||||
# Build the Go compiler.
|
# Build the Go compiler.
|
||||||
tinygo:
|
tinygo:
|
||||||
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " make llvm-source"; echo " make $(LLVM_BUILDDIR)"; exit 1; fi
|
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " make llvm-source"; echo " make $(LLVM_BUILDDIR)"; exit 1; fi
|
||||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
|
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
|
||||||
test: wasi-libc
|
test: wasi-libc check-nodejs-version
|
||||||
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 .
|
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 .
|
||||||
|
|
||||||
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
|
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
|
||||||
@@ -413,8 +427,12 @@ tinygo-bench-fast:
|
|||||||
# Same thing, except for wasi rather than the current platform.
|
# Same thing, except for wasi rather than the current platform.
|
||||||
tinygo-test-wasi:
|
tinygo-test-wasi:
|
||||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||||
|
tinygo-test-wasip1:
|
||||||
|
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||||
tinygo-test-wasi-fast:
|
tinygo-test-wasi-fast:
|
||||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||||
|
tinygo-test-wasip1-fast:
|
||||||
|
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||||
tinygo-bench-wasi:
|
tinygo-bench-wasi:
|
||||||
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
|
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
|
||||||
tinygo-bench-wasi-fast:
|
tinygo-bench-wasi-fast:
|
||||||
@@ -478,12 +496,16 @@ smoketest:
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/time-offset
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-mouse
|
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-mouse
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-keyboard
|
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-keyboard
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/i2c-target
|
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/i2c-target
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/watchdog
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
# test simulated boards on play.tinygo.org
|
# test simulated boards on play.tinygo.org
|
||||||
ifneq ($(WASM), 0)
|
ifneq ($(WASM), 0)
|
||||||
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
||||||
@@ -642,6 +664,8 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=gopher-badge examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=gopher-badge examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
# test pwm
|
# test pwm
|
||||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
|||||||
+19
-1
@@ -12,6 +12,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
wasm "github.com/aykevl/go-wasm"
|
||||||
"github.com/blakesmith/ar"
|
"github.com/blakesmith/ar"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -74,8 +75,25 @@ func makeArchive(arfile *os.File, objs []string) error {
|
|||||||
fileIndex int
|
fileIndex int
|
||||||
}{symbol.Name, i})
|
}{symbol.Name, i})
|
||||||
}
|
}
|
||||||
|
} else if dbg, err := wasm.Parse(objfile); err == nil {
|
||||||
|
for _, s := range dbg.Sections {
|
||||||
|
switch section := s.(type) {
|
||||||
|
case *wasm.SectionImport:
|
||||||
|
for _, ln := range section.Entries {
|
||||||
|
|
||||||
|
if ln.Kind != wasm.ExtKindFunction {
|
||||||
|
// Not a function
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
symbolTable = append(symbolTable, struct {
|
||||||
|
name string
|
||||||
|
fileIndex int
|
||||||
|
}{ln.Field, i})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("failed to open file %s as ELF or PE/COFF: %w", objpath, err)
|
return fmt.Errorf("failed to open file %s as WASM, ELF or PE/COFF: %w", objpath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close file, to avoid issues with too many open files (especially on
|
// Close file, to avoid issues with too many open files (especially on
|
||||||
|
|||||||
+11
-14
@@ -217,19 +217,27 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
var packageJobs []*compileJob
|
var packageJobs []*compileJob
|
||||||
packageActionIDJobs := make(map[string]*compileJob)
|
packageActionIDJobs := make(map[string]*compileJob)
|
||||||
|
|
||||||
|
if config.Options.GlobalValues == nil {
|
||||||
|
config.Options.GlobalValues = make(map[string]map[string]string)
|
||||||
|
}
|
||||||
if config.Options.GlobalValues["runtime"]["buildVersion"] == "" {
|
if config.Options.GlobalValues["runtime"]["buildVersion"] == "" {
|
||||||
version := goenv.Version
|
version := goenv.Version
|
||||||
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
|
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
|
||||||
version += "-" + goenv.GitSha1
|
version += "-" + goenv.GitSha1
|
||||||
}
|
}
|
||||||
if config.Options.GlobalValues == nil {
|
|
||||||
config.Options.GlobalValues = make(map[string]map[string]string)
|
|
||||||
}
|
|
||||||
if config.Options.GlobalValues["runtime"] == nil {
|
if config.Options.GlobalValues["runtime"] == nil {
|
||||||
config.Options.GlobalValues["runtime"] = make(map[string]string)
|
config.Options.GlobalValues["runtime"] = make(map[string]string)
|
||||||
}
|
}
|
||||||
config.Options.GlobalValues["runtime"]["buildVersion"] = version
|
config.Options.GlobalValues["runtime"]["buildVersion"] = version
|
||||||
}
|
}
|
||||||
|
if config.TestConfig.CompileTestBinary {
|
||||||
|
// The testing.testBinary is set to "1" when in a test.
|
||||||
|
// This is needed for testing.Testing() to work correctly.
|
||||||
|
if config.Options.GlobalValues["testing"] == nil {
|
||||||
|
config.Options.GlobalValues["testing"] = make(map[string]string)
|
||||||
|
}
|
||||||
|
config.Options.GlobalValues["testing"]["testBinary"] = "1"
|
||||||
|
}
|
||||||
|
|
||||||
var embedFileObjects []*compileJob
|
var embedFileObjects []*compileJob
|
||||||
for _, pkg := range lprogram.Sorted() {
|
for _, pkg := range lprogram.Sorted() {
|
||||||
@@ -1054,17 +1062,6 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Browsers cannot handle external functions that have type i64 because it
|
|
||||||
// cannot be represented exactly in JavaScript (JS only has doubles). To
|
|
||||||
// keep functions interoperable, pass int64 types as pointers to
|
|
||||||
// stack-allocated values.
|
|
||||||
if config.WasmAbi() == "js" {
|
|
||||||
err := transform.ExternalInt64AsPtr(mod, config)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optimization levels here are roughly the same as Clang, but probably not
|
// Optimization levels here are roughly the same as Clang, but probably not
|
||||||
// exactly.
|
// exactly.
|
||||||
optLevel, sizeLevel, inlinerThreshold := config.OptLevels()
|
optLevel, sizeLevel, inlinerThreshold := config.OptLevels()
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ func TestClangAttributes(t *testing.T) {
|
|||||||
{GOOS: "darwin", GOARCH: "arm64"},
|
{GOOS: "darwin", GOARCH: "arm64"},
|
||||||
{GOOS: "windows", GOARCH: "amd64"},
|
{GOOS: "windows", GOARCH: "amd64"},
|
||||||
{GOOS: "windows", GOARCH: "arm64"},
|
{GOOS: "windows", GOARCH: "arm64"},
|
||||||
|
{GOOS: "wasip1", GOARCH: "wasm"},
|
||||||
} {
|
} {
|
||||||
name := "GOOS=" + options.GOOS + ",GOARCH=" + options.GOARCH
|
name := "GOOS=" + options.GOOS + ",GOARCH=" + options.GOARCH
|
||||||
if options.GOARCH == "arm" {
|
if options.GOARCH == "arm" {
|
||||||
|
|||||||
+4
-10
@@ -1,7 +1,6 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/compileopts"
|
"github.com/tinygo-org/tinygo/compileopts"
|
||||||
@@ -24,19 +23,14 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
|||||||
spec.OpenOCDCommands = options.OpenOCDCommands
|
spec.OpenOCDCommands = options.OpenOCDCommands
|
||||||
}
|
}
|
||||||
|
|
||||||
goroot := goenv.Get("GOROOT")
|
major, minor, err := goenv.GetGorootVersion()
|
||||||
if goroot == "" {
|
|
||||||
return nil, errors.New("cannot locate $GOROOT, please set it manually")
|
|
||||||
}
|
|
||||||
|
|
||||||
major, minor, err := goenv.GetGorootVersion(goroot)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
if major != 1 || minor < 18 || minor > 20 {
|
if major != 1 || minor < 18 || minor > 21 {
|
||||||
// Note: when this gets updated, also update the Go compatibility matrix:
|
// Note: when this gets updated, also update the Go compatibility matrix:
|
||||||
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
||||||
return nil, fmt.Errorf("requires go version 1.18 through 1.20, got go%d.%d", major, minor)
|
return nil, fmt.Errorf("requires go version 1.18 through 1.21, got go%d.%d", major, minor)
|
||||||
}
|
}
|
||||||
|
|
||||||
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ func TestBinarySize(t *testing.T) {
|
|||||||
// microcontrollers
|
// microcontrollers
|
||||||
{"hifive1b", "examples/echo", 4612, 280, 0, 2252},
|
{"hifive1b", "examples/echo", 4612, 280, 0, 2252},
|
||||||
{"microbit", "examples/serial", 2724, 388, 8, 2256},
|
{"microbit", "examples/serial", 2724, 388, 8, 2256},
|
||||||
{"wioterminal", "examples/pininterrupt", 6159, 1485, 116, 6816},
|
{"wioterminal", "examples/pininterrupt", 6039, 1485, 116, 6816},
|
||||||
|
|
||||||
// TODO: also check wasm. Right now this is difficult, because
|
// TODO: also check wasm. Right now this is difficult, because
|
||||||
// wasm binaries are run through wasm-opt and therefore the
|
// wasm binaries are run through wasm-opt and therefore the
|
||||||
|
|||||||
@@ -492,11 +492,6 @@ func (c *Config) RelocationModel() string {
|
|||||||
return "static"
|
return "static"
|
||||||
}
|
}
|
||||||
|
|
||||||
// WasmAbi returns the WASM ABI which is specified in the target JSON file.
|
|
||||||
func (c *Config) WasmAbi() string {
|
|
||||||
return c.Target.WasmAbi
|
|
||||||
}
|
|
||||||
|
|
||||||
// EmulatorName is a shorthand to get the command for this emulator, something
|
// EmulatorName is a shorthand to get the command for this emulator, something
|
||||||
// like qemu-system-arm or simavr.
|
// like qemu-system-arm or simavr.
|
||||||
func (c *Config) EmulatorName() string {
|
func (c *Config) EmulatorName() string {
|
||||||
|
|||||||
+70
-41
@@ -23,46 +23,45 @@ import (
|
|||||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.TargetOptions.html
|
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.TargetOptions.html
|
||||||
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
|
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
|
||||||
type TargetSpec struct {
|
type TargetSpec struct {
|
||||||
Inherits []string `json:"inherits"`
|
Inherits []string `json:"inherits,omitempty"`
|
||||||
Triple string `json:"llvm-target"`
|
Triple string `json:"llvm-target,omitempty"`
|
||||||
CPU string `json:"cpu"`
|
CPU string `json:"cpu,omitempty"`
|
||||||
ABI string `json:"target-abi"` // rougly equivalent to -mabi= flag
|
ABI string `json:"target-abi,omitempty"` // rougly equivalent to -mabi= flag
|
||||||
Features string `json:"features"`
|
Features string `json:"features,omitempty"`
|
||||||
GOOS string `json:"goos"`
|
GOOS string `json:"goos,omitempty"`
|
||||||
GOARCH string `json:"goarch"`
|
GOARCH string `json:"goarch,omitempty"`
|
||||||
BuildTags []string `json:"build-tags"`
|
BuildTags []string `json:"build-tags,omitempty"`
|
||||||
GC string `json:"gc"`
|
GC string `json:"gc,omitempty"`
|
||||||
Scheduler string `json:"scheduler"`
|
Scheduler string `json:"scheduler,omitempty"`
|
||||||
Serial string `json:"serial"` // which serial output to use (uart, usb, none)
|
Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none)
|
||||||
Linker string `json:"linker"`
|
Linker string `json:"linker,omitempty"`
|
||||||
RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt)
|
RTLib string `json:"rtlib,omitempty"` // compiler runtime library (libgcc, compiler-rt)
|
||||||
Libc string `json:"libc"`
|
Libc string `json:"libc,omitempty"`
|
||||||
AutoStackSize *bool `json:"automatic-stack-size"` // Determine stack size automatically at compile time.
|
AutoStackSize *bool `json:"automatic-stack-size,omitempty"` // Determine stack size automatically at compile time.
|
||||||
DefaultStackSize uint64 `json:"default-stack-size"` // Default stack size if the size couldn't be determined at compile time.
|
DefaultStackSize uint64 `json:"default-stack-size,omitempty"` // Default stack size if the size couldn't be determined at compile time.
|
||||||
CFlags []string `json:"cflags"`
|
CFlags []string `json:"cflags,omitempty"`
|
||||||
LDFlags []string `json:"ldflags"`
|
LDFlags []string `json:"ldflags,omitempty"`
|
||||||
LinkerScript string `json:"linkerscript"`
|
LinkerScript string `json:"linkerscript,omitempty"`
|
||||||
ExtraFiles []string `json:"extra-files"`
|
ExtraFiles []string `json:"extra-files,omitempty"`
|
||||||
RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
|
RP2040BootPatch *bool `json:"rp2040-boot-patch,omitempty"` // Patch RP2040 2nd stage bootloader checksum
|
||||||
Emulator string `json:"emulator"`
|
Emulator string `json:"emulator,omitempty"`
|
||||||
FlashCommand string `json:"flash-command"`
|
FlashCommand string `json:"flash-command,omitempty"`
|
||||||
GDB []string `json:"gdb"`
|
GDB []string `json:"gdb,omitempty"`
|
||||||
PortReset string `json:"flash-1200-bps-reset"`
|
PortReset string `json:"flash-1200-bps-reset,omitempty"`
|
||||||
SerialPort []string `json:"serial-port"` // serial port IDs in the form "vid:pid"
|
SerialPort []string `json:"serial-port,omitempty"` // serial port IDs in the form "vid:pid"
|
||||||
FlashMethod string `json:"flash-method"`
|
FlashMethod string `json:"flash-method,omitempty"`
|
||||||
FlashVolume []string `json:"msd-volume-name"`
|
FlashVolume []string `json:"msd-volume-name,omitempty"`
|
||||||
FlashFilename string `json:"msd-firmware-name"`
|
FlashFilename string `json:"msd-firmware-name,omitempty"`
|
||||||
UF2FamilyID string `json:"uf2-family-id"`
|
UF2FamilyID string `json:"uf2-family-id,omitempty"`
|
||||||
BinaryFormat string `json:"binary-format"`
|
BinaryFormat string `json:"binary-format,omitempty"`
|
||||||
OpenOCDInterface string `json:"openocd-interface"`
|
OpenOCDInterface string `json:"openocd-interface,omitempty"`
|
||||||
OpenOCDTarget string `json:"openocd-target"`
|
OpenOCDTarget string `json:"openocd-target,omitempty"`
|
||||||
OpenOCDTransport string `json:"openocd-transport"`
|
OpenOCDTransport string `json:"openocd-transport,omitempty"`
|
||||||
OpenOCDCommands []string `json:"openocd-commands"`
|
OpenOCDCommands []string `json:"openocd-commands,omitempty"`
|
||||||
OpenOCDVerify *bool `json:"openocd-verify"` // enable verify when flashing with openocd
|
OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd
|
||||||
JLinkDevice string `json:"jlink-device"`
|
JLinkDevice string `json:"jlink-device,omitempty"`
|
||||||
CodeModel string `json:"code-model"`
|
CodeModel string `json:"code-model,omitempty"`
|
||||||
RelocationModel string `json:"relocation-model"`
|
RelocationModel string `json:"relocation-model,omitempty"`
|
||||||
WasmAbi string `json:"wasm-abi"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// overrideProperties overrides all properties that are set in child into itself using reflection.
|
// overrideProperties overrides all properties that are set in child into itself using reflection.
|
||||||
@@ -192,12 +191,15 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
|
|||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid GOARM=%s, must be 5, 6, or 7", options.GOARM)
|
return nil, fmt.Errorf("invalid GOARM=%s, must be 5, 6, or 7", options.GOARM)
|
||||||
}
|
}
|
||||||
|
case "wasm":
|
||||||
|
llvmarch = "wasm32"
|
||||||
default:
|
default:
|
||||||
llvmarch = options.GOARCH
|
llvmarch = options.GOARCH
|
||||||
}
|
}
|
||||||
llvmvendor := "unknown"
|
llvmvendor := "unknown"
|
||||||
llvmos := options.GOOS
|
llvmos := options.GOOS
|
||||||
if llvmos == "darwin" {
|
switch llvmos {
|
||||||
|
case "darwin":
|
||||||
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer
|
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer
|
||||||
// to iOS!
|
// to iOS!
|
||||||
llvmos = "macosx10.12.0"
|
llvmos = "macosx10.12.0"
|
||||||
@@ -208,6 +210,8 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
|
|||||||
llvmos = "macosx11.0.0"
|
llvmos = "macosx11.0.0"
|
||||||
}
|
}
|
||||||
llvmvendor = "apple"
|
llvmvendor = "apple"
|
||||||
|
case "wasip1":
|
||||||
|
llvmos = "wasi"
|
||||||
}
|
}
|
||||||
// Target triples (which actually have four components, but are called
|
// Target triples (which actually have four components, but are called
|
||||||
// triples for historical reasons) have the form:
|
// triples for historical reasons) have the form:
|
||||||
@@ -278,6 +282,15 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
case "arm64":
|
case "arm64":
|
||||||
spec.CPU = "generic"
|
spec.CPU = "generic"
|
||||||
spec.Features = "+neon"
|
spec.Features = "+neon"
|
||||||
|
case "wasm":
|
||||||
|
spec.CPU = "generic"
|
||||||
|
spec.Features = "+bulk-memory,+nontrapping-fptoint,+sign-ext"
|
||||||
|
spec.BuildTags = append(spec.BuildTags, "tinygo.wasm")
|
||||||
|
spec.CFlags = append(spec.CFlags,
|
||||||
|
"-mbulk-memory",
|
||||||
|
"-mnontrapping-fptoint",
|
||||||
|
"-msign-ext",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if goos == "darwin" {
|
if goos == "darwin" {
|
||||||
spec.Linker = "ld.lld"
|
spec.Linker = "ld.lld"
|
||||||
@@ -321,6 +334,22 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
"--no-insert-timestamp",
|
"--no-insert-timestamp",
|
||||||
"--no-dynamicbase",
|
"--no-dynamicbase",
|
||||||
)
|
)
|
||||||
|
} else if goos == "wasip1" {
|
||||||
|
spec.GC = "" // use default GC
|
||||||
|
spec.Scheduler = "asyncify"
|
||||||
|
spec.Linker = "wasm-ld"
|
||||||
|
spec.RTLib = "compiler-rt"
|
||||||
|
spec.Libc = "wasi-libc"
|
||||||
|
spec.DefaultStackSize = 1024 * 16 // 16kB
|
||||||
|
spec.LDFlags = append(spec.LDFlags,
|
||||||
|
"--stack-first",
|
||||||
|
"--no-demangle",
|
||||||
|
)
|
||||||
|
spec.Emulator = "wasmtime --mapdir=/tmp::{tmpDir} {}"
|
||||||
|
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||||
|
"src/runtime/asm_tinygowasm.S",
|
||||||
|
"src/internal/task/task_asyncify_wasm.S",
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
|
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-1
@@ -36,7 +36,11 @@ const (
|
|||||||
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
|
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
|
||||||
// createRuntimeInvoke instead.
|
// createRuntimeInvoke instead.
|
||||||
func (b *builder) createRuntimeCallCommon(fnName string, args []llvm.Value, name string, isInvoke bool) llvm.Value {
|
func (b *builder) createRuntimeCallCommon(fnName string, args []llvm.Value, name string, isInvoke bool) llvm.Value {
|
||||||
fn := b.program.ImportedPackage("runtime").Members[fnName].(*ssa.Function)
|
member := b.program.ImportedPackage("runtime").Members[fnName]
|
||||||
|
if member == nil {
|
||||||
|
panic("unknown runtime call: " + fnName)
|
||||||
|
}
|
||||||
|
fn := member.(*ssa.Function)
|
||||||
fnType, llvmFn := b.getFunction(fn)
|
fnType, llvmFn := b.getFunction(fn)
|
||||||
if llvmFn.IsNil() {
|
if llvmFn.IsNil() {
|
||||||
panic("trying to call non-existent function: " + fn.RelString(nil))
|
panic("trying to call non-existent function: " + fn.RelString(nil))
|
||||||
|
|||||||
@@ -1600,6 +1600,45 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
|||||||
cplx = b.CreateInsertValue(cplx, r, 0, "")
|
cplx = b.CreateInsertValue(cplx, r, 0, "")
|
||||||
cplx = b.CreateInsertValue(cplx, i, 1, "")
|
cplx = b.CreateInsertValue(cplx, i, 1, "")
|
||||||
return cplx, nil
|
return cplx, nil
|
||||||
|
case "clear":
|
||||||
|
value := argValues[0]
|
||||||
|
switch typ := argTypes[0].Underlying().(type) {
|
||||||
|
case *types.Slice:
|
||||||
|
elementType := b.getLLVMType(typ.Elem())
|
||||||
|
elementSize := b.targetData.TypeAllocSize(elementType)
|
||||||
|
elementAlign := b.targetData.ABITypeAlignment(elementType)
|
||||||
|
|
||||||
|
// The pointer to the data to be cleared.
|
||||||
|
llvmBuf := b.CreateExtractValue(value, 0, "buf")
|
||||||
|
if llvmBuf.Type() != b.i8ptrType { // compatibility with LLVM 14
|
||||||
|
llvmBuf = b.CreateBitCast(llvmBuf, b.i8ptrType, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
// The length (in bytes) to be cleared.
|
||||||
|
llvmLen := b.CreateExtractValue(value, 1, "len")
|
||||||
|
llvmLen = b.CreateMul(llvmLen, llvm.ConstInt(llvmLen.Type(), elementSize, false), "")
|
||||||
|
|
||||||
|
// Do the clear operation using the LLVM memset builtin.
|
||||||
|
// This is also correct for nil slices: in those cases, len will be
|
||||||
|
// 0 which means the memset call is a no-op (according to the LLVM
|
||||||
|
// LangRef).
|
||||||
|
memset := b.getMemsetFunc()
|
||||||
|
call := b.createCall(memset.GlobalValueType(), memset, []llvm.Value{
|
||||||
|
llvmBuf, // dest
|
||||||
|
llvm.ConstInt(b.ctx.Int8Type(), 0, false), // val
|
||||||
|
llvmLen, // len
|
||||||
|
llvm.ConstInt(b.ctx.Int1Type(), 0, false), // isVolatile
|
||||||
|
}, "")
|
||||||
|
call.AddCallSiteAttribute(1, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elementAlign)))
|
||||||
|
|
||||||
|
return llvm.Value{}, nil
|
||||||
|
case *types.Map:
|
||||||
|
m := argValues[0]
|
||||||
|
b.createMapClear(m)
|
||||||
|
return llvm.Value{}, nil
|
||||||
|
default:
|
||||||
|
return llvm.Value{}, b.makeError(pos, "unsupported type in clear builtin: "+typ.String())
|
||||||
|
}
|
||||||
case "copy":
|
case "copy":
|
||||||
dst := argValues[0]
|
dst := argValues[0]
|
||||||
src := argValues[1]
|
src := argValues[1]
|
||||||
@@ -1637,6 +1676,24 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
|||||||
llvmLen = b.CreateZExt(llvmLen, b.intType, "len.int")
|
llvmLen = b.CreateZExt(llvmLen, b.intType, "len.int")
|
||||||
}
|
}
|
||||||
return llvmLen, nil
|
return llvmLen, nil
|
||||||
|
case "min", "max":
|
||||||
|
// min and max builtins, added in Go 1.21.
|
||||||
|
// We can simply reuse the existing binop comparison code, which has all
|
||||||
|
// the edge cases figured out already.
|
||||||
|
tok := token.LSS
|
||||||
|
if callName == "max" {
|
||||||
|
tok = token.GTR
|
||||||
|
}
|
||||||
|
result := argValues[0]
|
||||||
|
typ := argTypes[0]
|
||||||
|
for _, arg := range argValues[1:] {
|
||||||
|
cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos)
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
result = b.CreateSelect(cmp, result, arg, "")
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
case "print", "println":
|
case "print", "println":
|
||||||
for i, value := range argValues {
|
for i, value := range argValues {
|
||||||
if i >= 1 && callName == "println" {
|
if i >= 1 && callName == "println" {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ func TestCompiler(t *testing.T) {
|
|||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
// Determine Go minor version (e.g. 16 in go1.16.3).
|
// Determine Go minor version (e.g. 16 in go1.16.3).
|
||||||
_, goMinor, err := goenv.GetGorootVersion(goenv.Get("GOROOT"))
|
_, goMinor, err := goenv.GetGorootVersion()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("could not read Go version:", err)
|
t.Fatal("could not read Go version:", err)
|
||||||
}
|
}
|
||||||
@@ -54,6 +54,9 @@ func TestCompiler(t *testing.T) {
|
|||||||
if goMinor >= 20 {
|
if goMinor >= 20 {
|
||||||
tests = append(tests, testCase{"go1.20.go", "", ""})
|
tests = append(tests, testCase{"go1.20.go", "", ""})
|
||||||
}
|
}
|
||||||
|
if goMinor >= 21 {
|
||||||
|
tests = append(tests, testCase{"go1.21.go", "", ""})
|
||||||
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
name := tc.file
|
name := tc.file
|
||||||
|
|||||||
+17
-8
@@ -128,6 +128,15 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
|||||||
hasMethodSet = false
|
hasMethodSet = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var numMethods int
|
||||||
|
if hasMethodSet {
|
||||||
|
for i := 0; i < ms.Len(); i++ {
|
||||||
|
if ms.At(i).Obj().Exported() {
|
||||||
|
numMethods++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Short-circuit all the global pointer logic here for pointers to pointers.
|
// Short-circuit all the global pointer logic here for pointers to pointers.
|
||||||
if typ, ok := typ.(*types.Pointer); ok {
|
if typ, ok := typ.(*types.Pointer); ok {
|
||||||
if _, ok := typ.Elem().(*types.Pointer); ok {
|
if _, ok := typ.Elem().(*types.Pointer); ok {
|
||||||
@@ -277,11 +286,11 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
|||||||
}
|
}
|
||||||
pkgPathPtr := c.pkgPathPtr(pkgpath)
|
pkgPathPtr := c.pkgPathPtr(pkgpath)
|
||||||
typeFields = []llvm.Value{
|
typeFields = []llvm.Value{
|
||||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods
|
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||||
c.getTypeCode(typ.Underlying()), // underlying
|
c.getTypeCode(typ.Underlying()), // underlying
|
||||||
pkgPathPtr, // pkgpath pointer
|
pkgPathPtr, // pkgpath pointer
|
||||||
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
|
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
|
||||||
}
|
}
|
||||||
metabyte |= 1 << 5 // "named" flag
|
metabyte |= 1 << 5 // "named" flag
|
||||||
case *types.Chan:
|
case *types.Chan:
|
||||||
@@ -308,7 +317,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
|||||||
}
|
}
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
typeFields = []llvm.Value{
|
typeFields = []llvm.Value{
|
||||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods
|
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||||
c.getTypeCode(typ.Elem()),
|
c.getTypeCode(typ.Elem()),
|
||||||
}
|
}
|
||||||
case *types.Array:
|
case *types.Array:
|
||||||
@@ -337,8 +346,8 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
|||||||
llvmStructType := c.getLLVMType(typ)
|
llvmStructType := c.getLLVMType(typ)
|
||||||
size := c.targetData.TypeStoreSize(llvmStructType)
|
size := c.targetData.TypeStoreSize(llvmStructType)
|
||||||
typeFields = []llvm.Value{
|
typeFields = []llvm.Value{
|
||||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods
|
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||||
pkgPathPtr,
|
pkgPathPtr,
|
||||||
llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size
|
llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size
|
||||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
|
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
|
||||||
|
|||||||
+15
-9
@@ -70,15 +70,7 @@ func (b *builder) createMemoryCopyImpl() {
|
|||||||
// regular libc memset calls if they aren't optimized out in a different way.
|
// regular libc memset calls if they aren't optimized out in a different way.
|
||||||
func (b *builder) createMemoryZeroImpl() {
|
func (b *builder) createMemoryZeroImpl() {
|
||||||
b.createFunctionStart(true)
|
b.createFunctionStart(true)
|
||||||
fnName := "llvm.memset.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
llvmFn := b.getMemsetFunc()
|
||||||
if llvmutil.Major() < 15 { // compatibility with LLVM 14
|
|
||||||
fnName = "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
|
||||||
}
|
|
||||||
llvmFn := b.mod.NamedFunction(fnName)
|
|
||||||
if llvmFn.IsNil() {
|
|
||||||
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.ctx.Int8Type(), b.uintptrType, b.ctx.Int1Type()}, false)
|
|
||||||
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
|
|
||||||
}
|
|
||||||
params := []llvm.Value{
|
params := []llvm.Value{
|
||||||
b.getValue(b.fn.Params[0], getPos(b.fn)),
|
b.getValue(b.fn.Params[0], getPos(b.fn)),
|
||||||
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
|
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
|
||||||
@@ -89,6 +81,20 @@ func (b *builder) createMemoryZeroImpl() {
|
|||||||
b.CreateRetVoid()
|
b.CreateRetVoid()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the llvm.memset.p0.i8 function declaration.
|
||||||
|
func (c *compilerContext) getMemsetFunc() llvm.Value {
|
||||||
|
fnName := "llvm.memset.p0.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
|
||||||
|
if llvmutil.Major() < 15 { // compatibility with LLVM 14
|
||||||
|
fnName = "llvm.memset.p0i8.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
|
||||||
|
}
|
||||||
|
llvmFn := c.mod.NamedFunction(fnName)
|
||||||
|
if llvmFn.IsNil() {
|
||||||
|
fnType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType, c.ctx.Int8Type(), c.uintptrType, c.ctx.Int1Type()}, false)
|
||||||
|
llvmFn = llvm.AddFunction(c.mod, fnName, fnType)
|
||||||
|
}
|
||||||
|
return llvmFn
|
||||||
|
}
|
||||||
|
|
||||||
// createKeepAlive creates the runtime.KeepAlive function. It is implemented
|
// createKeepAlive creates the runtime.KeepAlive function. It is implemented
|
||||||
// using inline assembly.
|
// using inline assembly.
|
||||||
func (b *builder) createKeepAliveImpl() {
|
func (b *builder) createKeepAliveImpl() {
|
||||||
|
|||||||
@@ -185,6 +185,11 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Clear the given map.
|
||||||
|
func (b *builder) createMapClear(m llvm.Value) {
|
||||||
|
b.createRuntimeCall("hashmapClear", []llvm.Value{m}, "")
|
||||||
|
}
|
||||||
|
|
||||||
// createMapIteratorNext lowers the *ssa.Next instruction for iterating over a
|
// createMapIteratorNext lowers the *ssa.Next instruction for iterating over a
|
||||||
// map. It returns a tuple of {bool, key, value} with the result of the
|
// map. It returns a tuple of {bool, key, value} with the result of the
|
||||||
// iteration.
|
// iteration.
|
||||||
|
|||||||
+14
-33
@@ -23,9 +23,9 @@ import (
|
|||||||
// The linkName value contains a valid link name, even if //go:linkname is not
|
// The linkName value contains a valid link name, even if //go:linkname is not
|
||||||
// present.
|
// present.
|
||||||
type functionInfo struct {
|
type functionInfo struct {
|
||||||
module string // go:wasm-module
|
wasmModule string // go:wasm-module
|
||||||
importName string // go:linkname, go:export - The name the developer assigns
|
wasmName string // wasm-export-name or wasm-import-name in the IR
|
||||||
linkName string // go:linkname, go:export - The name that we map for the particular module -> importName
|
linkName string // go:linkname, go:export - the IR function name
|
||||||
section string // go:section - object file section name
|
section string // go:section - object file section name
|
||||||
exported bool // go:export, CGo
|
exported bool // go:export, CGo
|
||||||
interrupt bool // go:interrupt
|
interrupt bool // go:interrupt
|
||||||
@@ -194,20 +194,14 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
|||||||
// External/exported functions may not retain pointer values.
|
// External/exported functions may not retain pointer values.
|
||||||
// https://golang.org/cmd/cgo/#hdr-Passing_pointers
|
// https://golang.org/cmd/cgo/#hdr-Passing_pointers
|
||||||
if info.exported {
|
if info.exported {
|
||||||
if c.archFamily() == "wasm32" {
|
if c.archFamily() == "wasm32" && len(fn.Blocks) == 0 {
|
||||||
// We need to add the wasm-import-module and the wasm-import-name
|
// We need to add the wasm-import-module and the wasm-import-name
|
||||||
// attributes.
|
// attributes.
|
||||||
module := info.module
|
if info.wasmModule != "" {
|
||||||
if module == "" {
|
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", info.wasmModule))
|
||||||
module = "env"
|
|
||||||
}
|
}
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", module))
|
|
||||||
|
|
||||||
name := info.importName
|
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", info.wasmName))
|
||||||
if name == "" {
|
|
||||||
name = info.linkName
|
|
||||||
}
|
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", name))
|
|
||||||
}
|
}
|
||||||
nocaptureKind := llvm.AttributeKindID("nocapture")
|
nocaptureKind := llvm.AttributeKindID("nocapture")
|
||||||
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
|
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
|
||||||
@@ -260,10 +254,6 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if decl, ok := f.Syntax().(*ast.FuncDecl); ok && decl.Doc != nil {
|
if decl, ok := f.Syntax().(*ast.FuncDecl); ok && decl.Doc != nil {
|
||||||
|
|
||||||
// Our importName for a wasm module (if we are compiling to wasm), or llvm link name
|
|
||||||
var importName string
|
|
||||||
|
|
||||||
for _, comment := range decl.Doc.List {
|
for _, comment := range decl.Doc.List {
|
||||||
text := comment.Text
|
text := comment.Text
|
||||||
if strings.HasPrefix(text, "//export ") {
|
if strings.HasPrefix(text, "//export ") {
|
||||||
@@ -281,7 +271,8 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
importName = parts[1]
|
info.linkName = parts[1]
|
||||||
|
info.wasmName = info.linkName
|
||||||
info.exported = true
|
info.exported = true
|
||||||
case "//go:interrupt":
|
case "//go:interrupt":
|
||||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||||
@@ -289,10 +280,11 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
|||||||
}
|
}
|
||||||
case "//go:wasm-module":
|
case "//go:wasm-module":
|
||||||
// Alternative comment for setting the import module.
|
// Alternative comment for setting the import module.
|
||||||
|
// This is deprecated, use //go:wasmimport instead.
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
info.module = parts[1]
|
info.wasmModule = parts[1]
|
||||||
case "//go:wasmimport":
|
case "//go:wasmimport":
|
||||||
// Import a WebAssembly function, for example a WASI function.
|
// Import a WebAssembly function, for example a WASI function.
|
||||||
// Original proposal: https://github.com/golang/go/issues/38248
|
// Original proposal: https://github.com/golang/go/issues/38248
|
||||||
@@ -302,8 +294,8 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
|||||||
}
|
}
|
||||||
c.checkWasmImport(f, comment.Text)
|
c.checkWasmImport(f, comment.Text)
|
||||||
info.exported = true
|
info.exported = true
|
||||||
info.module = parts[1]
|
info.wasmModule = parts[1]
|
||||||
info.importName = parts[2]
|
info.wasmName = parts[2]
|
||||||
case "//go:inline":
|
case "//go:inline":
|
||||||
info.inline = inlineHint
|
info.inline = inlineHint
|
||||||
case "//go:noinline":
|
case "//go:noinline":
|
||||||
@@ -347,17 +339,6 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the importName for our exported function if we have one
|
|
||||||
if importName != "" {
|
|
||||||
if info.module == "" {
|
|
||||||
info.linkName = importName
|
|
||||||
} else {
|
|
||||||
// WebAssembly import
|
|
||||||
info.importName = importName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -367,7 +348,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
|||||||
// The list of allowed types is based on this proposal:
|
// The list of allowed types is based on this proposal:
|
||||||
// https://github.com/golang/go/issues/59149
|
// https://github.com/golang/go/issues/59149
|
||||||
func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
|
func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
|
||||||
if c.pkg.Path() == "runtime" {
|
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" {
|
||||||
// The runtime is a special case. Allow all kinds of parameters
|
// The runtime is a special case. Allow all kinds of parameters
|
||||||
// (importantly, including pointers).
|
// (importantly, including pointers).
|
||||||
return
|
return
|
||||||
|
|||||||
Vendored
+65
@@ -0,0 +1,65 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
func min1(a int) int {
|
||||||
|
return min(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func min2(a, b int) int {
|
||||||
|
return min(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func min3(a, b, c int) int {
|
||||||
|
return min(a, b, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func min4(a, b, c, d int) int {
|
||||||
|
return min(a, b, c, d)
|
||||||
|
}
|
||||||
|
|
||||||
|
func minUint8(a, b uint8) uint8 {
|
||||||
|
return min(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func minUnsigned(a, b uint) uint {
|
||||||
|
return min(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func minFloat32(a, b float32) float32 {
|
||||||
|
return min(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func minFloat64(a, b float64) float64 {
|
||||||
|
return min(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func minString(a, b string) string {
|
||||||
|
return min(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func maxInt(a, b int) int {
|
||||||
|
return max(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func maxUint(a, b uint) uint {
|
||||||
|
return max(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func maxFloat32(a, b float32) float32 {
|
||||||
|
return max(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func maxString(a, b string) string {
|
||||||
|
return max(a, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearSlice(s []int) {
|
||||||
|
clear(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearZeroSizedSlice(s []struct{}) {
|
||||||
|
clear(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearMap(m map[string]int) {
|
||||||
|
clear(m)
|
||||||
|
}
|
||||||
Vendored
+179
@@ -0,0 +1,179 @@
|
|||||||
|
; ModuleID = 'go1.21.go'
|
||||||
|
source_filename = "go1.21.go"
|
||||||
|
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||||
|
target triple = "wasm32-unknown-wasi"
|
||||||
|
|
||||||
|
%runtime._string = type { ptr, i32 }
|
||||||
|
|
||||||
|
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||||
|
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||||
|
|
||||||
|
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
ret i32 %a
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||||
|
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
|
||||||
|
ret i32 %1
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||||
|
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
|
||||||
|
%2 = call i32 @llvm.smin.i32(i32 %1, i32 %d)
|
||||||
|
ret i32 %2
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = call i8 @llvm.umin.i8(i8 %a, i8 %b)
|
||||||
|
ret i8 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = fcmp olt float %a, %b
|
||||||
|
%1 = select i1 %0, float %a, float %b
|
||||||
|
ret float %1
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = fcmp olt double %a, %b
|
||||||
|
%1 = select i1 %0, double %a, double %b
|
||||||
|
ret double %1
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden %runtime._string @main.minString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
|
||||||
|
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
|
||||||
|
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
|
||||||
|
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
|
||||||
|
%stackalloc = alloca i8, align 1
|
||||||
|
%4 = call i1 @runtime.stringLess(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr undef) #5
|
||||||
|
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
|
||||||
|
%6 = extractvalue %runtime._string %5, 0
|
||||||
|
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
|
ret %runtime._string %5
|
||||||
|
}
|
||||||
|
|
||||||
|
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
|
||||||
|
ret i32 %0
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = fcmp ogt float %a, %b
|
||||||
|
%1 = select i1 %0, float %a, float %b
|
||||||
|
ret float %1
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden %runtime._string @main.maxString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
|
||||||
|
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
|
||||||
|
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
|
||||||
|
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
|
||||||
|
%stackalloc = alloca i8, align 1
|
||||||
|
%4 = call i1 @runtime.stringLess(ptr %b.data, i32 %b.len, ptr %a.data, i32 %a.len, ptr undef) #5
|
||||||
|
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
|
||||||
|
%6 = extractvalue %runtime._string %5, 0
|
||||||
|
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
|
||||||
|
ret %runtime._string %5
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
%0 = shl i32 %s.len, 2
|
||||||
|
call void @llvm.memset.p0.i32(ptr align 4 %s.data, i8 0, i32 %0, i1 false)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: argmemonly nocallback nofree nounwind willreturn writeonly
|
||||||
|
declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #3
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define hidden void @main.clearMap(ptr dereferenceable_or_null(40) %m, ptr %context) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
call void @runtime.hashmapClear(ptr %m, ptr undef) #5
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #1
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
||||||
|
declare i32 @llvm.smin.i32(i32, i32) #4
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
||||||
|
declare i8 @llvm.umin.i8(i8, i8) #4
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
||||||
|
declare i32 @llvm.umin.i32(i32, i32) #4
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
||||||
|
declare i32 @llvm.smax.i32(i32, i32) #4
|
||||||
|
|
||||||
|
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
||||||
|
declare i32 @llvm.umax.i32(i32, i32) #4
|
||||||
|
|
||||||
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
|
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
|
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
|
attributes #3 = { argmemonly nocallback nofree nounwind willreturn writeonly }
|
||||||
|
attributes #4 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
|
||||||
|
attributes #5 = { nounwind }
|
||||||
Vendored
+1
-1
@@ -9,7 +9,7 @@ target triple = "wasm32-unknown-wasi"
|
|||||||
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
||||||
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
|
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
|
||||||
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
|
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
|
||||||
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 1, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
|
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 0, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
|
||||||
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
|
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
|
||||||
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
|
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||||
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
|
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||||
|
|||||||
Vendored
+13
@@ -62,6 +62,19 @@ func exportedFunctionInSection() {
|
|||||||
//go:wasmimport modulename import1
|
//go:wasmimport modulename import1
|
||||||
func declaredImport()
|
func declaredImport()
|
||||||
|
|
||||||
|
// Legacy way of importing a function.
|
||||||
|
//
|
||||||
|
//go:wasm-module foobar
|
||||||
|
//export imported
|
||||||
|
func foobarImport()
|
||||||
|
|
||||||
|
// The wasm-module pragma is not functional here, but it should be safe.
|
||||||
|
//
|
||||||
|
//go:wasm-module foobar
|
||||||
|
//export exported
|
||||||
|
func foobarExportModule() {
|
||||||
|
}
|
||||||
|
|
||||||
// This function should not: it's only a declaration and not a definition.
|
// This function should not: it's only a declaration and not a definition.
|
||||||
//
|
//
|
||||||
//go:section .special_function_section
|
//go:section .special_function_section
|
||||||
|
|||||||
Vendored
+13
-3
@@ -6,7 +6,7 @@ target triple = "wasm32-unknown-wasi"
|
|||||||
@extern_global = external global [0 x i8], align 1
|
@extern_global = external global [0 x i8], align 1
|
||||||
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
|
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
|
||||||
@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16
|
@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16
|
||||||
@llvm.used = appending global [2 x ptr] [ptr @extern_func, ptr @exportedFunctionInSection]
|
@llvm.used = appending global [3 x ptr] [ptr @extern_func, ptr @exportedFunctionInSection, ptr @exported]
|
||||||
@main.globalInSection = hidden global i32 0, section ".special_global_section", align 4
|
@main.globalInSection = hidden global i32 0, section ".special_global_section", align 4
|
||||||
@undefinedGlobalNotInSection = external global i32, align 4
|
@undefinedGlobalNotInSection = external global i32, align 4
|
||||||
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
|
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
|
||||||
@@ -62,13 +62,23 @@ entry:
|
|||||||
|
|
||||||
declare void @main.declaredImport() #7
|
declare void @main.declaredImport() #7
|
||||||
|
|
||||||
|
declare void @imported() #8
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define void @exported() #9 {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
declare void @main.undefinedFunctionNotInSection(ptr) #1
|
declare void @main.undefinedFunctionNotInSection(ptr) #1
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #3 = { 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 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" }
|
||||||
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" }
|
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" }
|
||||||
attributes #7 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
attributes #7 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
||||||
|
attributes #8 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
|
||||||
|
attributes #9 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exported" }
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ require (
|
|||||||
github.com/mattn/go-colorable v0.1.8
|
github.com/mattn/go-colorable v0.1.8
|
||||||
github.com/mattn/go-tty v0.0.4
|
github.com/mattn/go-tty v0.0.4
|
||||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
||||||
go.bug.st/serial v1.3.5
|
go.bug.st/serial v1.6.0
|
||||||
golang.org/x/sys v0.4.0
|
golang.org/x/sys v0.4.0
|
||||||
golang.org/x/tools v0.5.1-0.20230114154351-e035d0c426c8
|
golang.org/x/tools v0.5.1-0.20230114154351-e035d0c426c8
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ 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 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
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 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||||
|
github.com/deadprogram/go-serial v0.0.0-20230717164825-4529b3232919 h1:Hi7G1bCG70NwlyqGswJKEHoIi4hJVN1SsmfwZ+DQHtw=
|
||||||
|
github.com/deadprogram/go-serial v0.0.0-20230717164825-4529b3232919/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
||||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
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/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||||
@@ -46,8 +48,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
||||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
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.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
|
||||||
go.bug.st/serial v1.3.5/go.mod h1:z8CesKorE90Qr/oRSJiEuvzYRKol9r/anJZEb5kt304=
|
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
||||||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
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-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
|||||||
+53
-99
@@ -4,15 +4,16 @@ package goenv
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/user"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Keys is a slice of all available environment variable keys.
|
// Keys is a slice of all available environment variable keys.
|
||||||
@@ -37,6 +38,53 @@ func init() {
|
|||||||
// directory.
|
// directory.
|
||||||
var TINYGOROOT string
|
var TINYGOROOT string
|
||||||
|
|
||||||
|
// Variables read from a `go env` command invocation.
|
||||||
|
var goEnvVars struct {
|
||||||
|
GOPATH string
|
||||||
|
GOROOT string
|
||||||
|
GOVERSION string
|
||||||
|
}
|
||||||
|
|
||||||
|
var goEnvVarsOnce sync.Once
|
||||||
|
var goEnvVarsErr error // error returned from cmd.Run
|
||||||
|
|
||||||
|
// Make sure goEnvVars is fresh. This can be called multiple times, the first
|
||||||
|
// time will update all environment variables in goEnvVars.
|
||||||
|
func readGoEnvVars() error {
|
||||||
|
goEnvVarsOnce.Do(func() {
|
||||||
|
cmd := exec.Command("go", "env", "-json", "GOPATH", "GOROOT", "GOVERSION")
|
||||||
|
output, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
// Check for "command not found" error.
|
||||||
|
if execErr, ok := err.(*exec.Error); ok {
|
||||||
|
goEnvVarsErr = fmt.Errorf("could not find '%s' command: %w", execErr.Name, execErr.Err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// It's perhaps a bit ugly to handle this error here, but I couldn't
|
||||||
|
// think of a better place further up in the call chain.
|
||||||
|
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() != 0 {
|
||||||
|
if len(exitErr.Stderr) != 0 {
|
||||||
|
// The 'go' command exited with an error message. Print that
|
||||||
|
// message and exit, so we behave in a similar way.
|
||||||
|
os.Stderr.Write(exitErr.Stderr)
|
||||||
|
os.Exit(exitErr.ExitCode())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Other errors. Not sure whether there are any, but just in case.
|
||||||
|
goEnvVarsErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(output, &goEnvVars)
|
||||||
|
if err != nil {
|
||||||
|
// This should never happen if we have a sane Go toolchain
|
||||||
|
// installed.
|
||||||
|
goEnvVarsErr = fmt.Errorf("unexpected error while unmarshalling `go env` output: %w", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return goEnvVarsErr
|
||||||
|
}
|
||||||
|
|
||||||
// Get returns a single environment variable, possibly calculating it on-demand.
|
// Get returns a single environment variable, possibly calculating it on-demand.
|
||||||
// The empty string is returned for unknown environment variables.
|
// The empty string is returned for unknown environment variables.
|
||||||
func Get(name string) string {
|
func Get(name string) string {
|
||||||
@@ -70,15 +118,11 @@ func Get(name string) string {
|
|||||||
// especially when floating point instructions are involved.
|
// especially when floating point instructions are involved.
|
||||||
return "6"
|
return "6"
|
||||||
case "GOROOT":
|
case "GOROOT":
|
||||||
return getGoroot()
|
readGoEnvVars()
|
||||||
|
return goEnvVars.GOROOT
|
||||||
case "GOPATH":
|
case "GOPATH":
|
||||||
if dir := os.Getenv("GOPATH"); dir != "" {
|
readGoEnvVars()
|
||||||
return dir
|
return goEnvVars.GOPATH
|
||||||
}
|
|
||||||
|
|
||||||
// fallback
|
|
||||||
home := getHomeDir()
|
|
||||||
return filepath.Join(home, "go")
|
|
||||||
case "GOCACHE":
|
case "GOCACHE":
|
||||||
// Get the cache directory, usually ~/.cache/tinygo
|
// Get the cache directory, usually ~/.cache/tinygo
|
||||||
dir, err := os.UserCacheDir()
|
dir, err := os.UserCacheDir()
|
||||||
@@ -240,93 +284,3 @@ func isSourceDir(root string) bool {
|
|||||||
_, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go"))
|
_, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go"))
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getHomeDir() string {
|
|
||||||
u, err := user.Current()
|
|
||||||
if err != nil {
|
|
||||||
panic("cannot get current user: " + err.Error())
|
|
||||||
}
|
|
||||||
if u.HomeDir == "" {
|
|
||||||
// This is very unlikely, so panic here.
|
|
||||||
// Not the nicest solution, however.
|
|
||||||
panic("could not find home directory")
|
|
||||||
}
|
|
||||||
return u.HomeDir
|
|
||||||
}
|
|
||||||
|
|
||||||
// getGoroot returns an appropriate GOROOT from various sources. If it can't be
|
|
||||||
// found, it returns an empty string.
|
|
||||||
func getGoroot() string {
|
|
||||||
// An explicitly set GOROOT always has preference.
|
|
||||||
goroot := os.Getenv("GOROOT")
|
|
||||||
if goroot != "" {
|
|
||||||
// Convert to the standard GOROOT being referenced, if it's a TinyGo cache.
|
|
||||||
return getStandardGoroot(goroot)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for the location of the 'go' binary and base GOROOT on that.
|
|
||||||
binpath, err := exec.LookPath("go")
|
|
||||||
if err == nil {
|
|
||||||
binpath, err = filepath.EvalSymlinks(binpath)
|
|
||||||
if err == nil {
|
|
||||||
goroot := filepath.Dir(filepath.Dir(binpath))
|
|
||||||
if isGoroot(goroot) {
|
|
||||||
return goroot
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check what GOROOT was at compile time.
|
|
||||||
if isGoroot(runtime.GOROOT()) {
|
|
||||||
return runtime.GOROOT()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for some standard locations, as a last resort.
|
|
||||||
var candidates []string
|
|
||||||
switch runtime.GOOS {
|
|
||||||
case "linux":
|
|
||||||
candidates = []string{
|
|
||||||
"/usr/local/go", // manually installed
|
|
||||||
"/usr/lib/go", // from the distribution
|
|
||||||
"/snap/go/current/", // installed using snap
|
|
||||||
}
|
|
||||||
case "darwin":
|
|
||||||
candidates = []string{
|
|
||||||
"/usr/local/go", // manually installed
|
|
||||||
"/usr/local/opt/go/libexec", // from Homebrew
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, candidate := range candidates {
|
|
||||||
if isGoroot(candidate) {
|
|
||||||
return candidate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Can't find GOROOT...
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// isGoroot checks whether the given path looks like a GOROOT.
|
|
||||||
func isGoroot(goroot string) bool {
|
|
||||||
_, err := os.Stat(filepath.Join(goroot, "src", "runtime", "internal", "sys", "zversion.go"))
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getStandardGoroot returns the physical path to a real, standard Go GOROOT
|
|
||||||
// implied by the given path.
|
|
||||||
// If the given path appears to be a TinyGo cached GOROOT, it returns the path
|
|
||||||
// referenced by symlinks contained in the cache. Otherwise, it returns the
|
|
||||||
// given path as-is.
|
|
||||||
func getStandardGoroot(path string) string {
|
|
||||||
// Check if the "bin" subdirectory of our given GOROOT is a symlink, and then
|
|
||||||
// return the _parent_ directory of its destination.
|
|
||||||
if dest, err := os.Readlink(filepath.Join(path, "bin")); nil == err {
|
|
||||||
// Clean the destination to remove any trailing slashes, so that
|
|
||||||
// filepath.Dir will always return the parent.
|
|
||||||
// (because both "/foo" and "/foo/" are valid symlink destinations,
|
|
||||||
// but filepath.Dir would return "/" and "/foo", respectively)
|
|
||||||
return filepath.Dir(filepath.Clean(dest))
|
|
||||||
}
|
|
||||||
return path
|
|
||||||
}
|
|
||||||
|
|||||||
+8
-26
@@ -4,15 +4,12 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Version of TinyGo.
|
// Version of TinyGo.
|
||||||
// Update this value before release of new version of software.
|
// Update this value before release of new version of software.
|
||||||
const Version = "0.28.0-dev"
|
const Version = "0.29.0"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// This variable is set at build time using -ldflags parameters.
|
// This variable is set at build time using -ldflags parameters.
|
||||||
@@ -22,8 +19,8 @@ var (
|
|||||||
|
|
||||||
// GetGorootVersion returns the major and minor version for a given GOROOT path.
|
// GetGorootVersion returns the major and minor version for a given GOROOT path.
|
||||||
// If the goroot cannot be determined, (0, 0) is returned.
|
// If the goroot cannot be determined, (0, 0) is returned.
|
||||||
func GetGorootVersion(goroot string) (major, minor int, err error) {
|
func GetGorootVersion() (major, minor int, err error) {
|
||||||
s, err := GorootVersionString(goroot)
|
s, err := GorootVersionString()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, 0, err
|
||||||
}
|
}
|
||||||
@@ -51,24 +48,9 @@ func GetGorootVersion(goroot string) (major, minor int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GorootVersionString returns the version string as reported by the Go
|
// GorootVersionString returns the version string as reported by the Go
|
||||||
// toolchain for the given GOROOT path. It is usually of the form `go1.x.y` but
|
// toolchain. It is usually of the form `go1.x.y` but can have some variations
|
||||||
// can have some variations (for beta releases, for example).
|
// (for beta releases, for example).
|
||||||
func GorootVersionString(goroot string) (string, error) {
|
func GorootVersionString() (string, error) {
|
||||||
if data, err := os.ReadFile(filepath.Join(goroot, "VERSION")); err == nil {
|
err := readGoEnvVars()
|
||||||
return string(data), nil
|
return goEnvVars.GOVERSION, err
|
||||||
|
|
||||||
} else if data, err := os.ReadFile(filepath.Join(
|
|
||||||
goroot, "src", "internal", "buildcfg", "zbootstrap.go")); err == nil {
|
|
||||||
|
|
||||||
r := regexp.MustCompile("const version = `(.*)`")
|
|
||||||
matches := r.FindSubmatch(data)
|
|
||||||
if len(matches) != 2 {
|
|
||||||
return "", errors.New("Invalid go version output:\n" + string(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(matches[1]), nil
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Submodule
+1
Submodule lib/renesas-svd added at 03d7688085
@@ -207,6 +207,11 @@ func listGorootMergeLinks(goroot, tinygoroot string, overrides map[string]bool)
|
|||||||
merges[dir] = filepath.Join(goroot, dir)
|
merges[dir] = filepath.Join(goroot, dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Required starting in Go 1.21 due to https://github.com/golang/go/issues/61928
|
||||||
|
if _, err := os.Stat(filepath.Join(goroot, "go.env")); err == nil {
|
||||||
|
merges["go.env"] = filepath.Join(goroot, "go.env")
|
||||||
|
}
|
||||||
|
|
||||||
return merges, nil
|
return merges, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@@ -946,112 +947,130 @@ func touchSerialPortAt1200bps(port string) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func flashUF2UsingMSD(volumes []string, tmppath string, options *compileopts.Options) error {
|
func flashUF2UsingMSD(volumes []string, tmppath string, options *compileopts.Options) error {
|
||||||
// find standard UF2 info path
|
for start := time.Now(); time.Since(start) < options.Timeout; {
|
||||||
infoPaths := make([]string, 0, len(volumes))
|
// Find a UF2 mount point.
|
||||||
for _, volume := range volumes {
|
mounts, err := findFATMounts(options)
|
||||||
switch runtime.GOOS {
|
if err != nil {
|
||||||
case "linux", "freebsd":
|
return err
|
||||||
fi, err := os.Stat("/run/media")
|
}
|
||||||
if err != nil || !fi.IsDir() {
|
for _, mount := range mounts {
|
||||||
infoPaths = append(infoPaths, "/media/*/"+volume+"/INFO_UF2.TXT")
|
for _, volume := range volumes {
|
||||||
} else {
|
if mount.name != volume {
|
||||||
infoPaths = append(infoPaths, "/run/media/*/"+volume+"/INFO_UF2.TXT")
|
continue
|
||||||
}
|
}
|
||||||
case "darwin":
|
if _, err := os.Stat(filepath.Join(mount.path, "INFO_UF2.TXT")); err != nil {
|
||||||
infoPaths = append(infoPaths, "/Volumes/"+volume+"/INFO_UF2.TXT")
|
// No INFO_UF2.TXT found, which is expected on a UF2
|
||||||
case "windows":
|
// filesystem.
|
||||||
path, err := windowsFindUSBDrive(volume, options)
|
continue
|
||||||
if err == nil {
|
}
|
||||||
infoPaths = append(infoPaths, path+"/INFO_UF2.TXT")
|
// Found the filesystem, so flash the device!
|
||||||
|
return moveFile(tmppath, filepath.Join(mount.path, "flash.uf2"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
time.Sleep(500 * time.Millisecond)
|
||||||
}
|
}
|
||||||
|
return errors.New("unable to locate any volume: [" + strings.Join(volumes, ",") + "]")
|
||||||
d, err := locateDevice(volumes, infoPaths, options.Timeout)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return moveFile(tmppath, filepath.Dir(d)+"/flash.uf2")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func flashHexUsingMSD(volumes []string, tmppath string, options *compileopts.Options) error {
|
func flashHexUsingMSD(volumes []string, tmppath string, options *compileopts.Options) error {
|
||||||
// find expected volume path
|
for start := time.Now(); time.Since(start) < options.Timeout; {
|
||||||
destPaths := make([]string, 0, len(volumes))
|
// Find all mount points.
|
||||||
for _, volume := range volumes {
|
mounts, err := findFATMounts(options)
|
||||||
switch runtime.GOOS {
|
if err != nil {
|
||||||
case "linux", "freebsd":
|
return err
|
||||||
fi, err := os.Stat("/run/media")
|
}
|
||||||
if err != nil || !fi.IsDir() {
|
for _, mount := range mounts {
|
||||||
destPaths = append(destPaths, "/media/*/"+volume)
|
for _, volume := range volumes {
|
||||||
} else {
|
if mount.name != volume {
|
||||||
destPaths = append(destPaths, "/run/media/*/"+volume)
|
continue
|
||||||
}
|
}
|
||||||
case "darwin":
|
// Found the filesystem, so flash the device!
|
||||||
destPaths = append(destPaths, "/Volumes/"+volume)
|
return moveFile(tmppath, filepath.Join(mount.path, "flash.hex"))
|
||||||
case "windows":
|
|
||||||
path, err := windowsFindUSBDrive(volume, options)
|
|
||||||
if err == nil {
|
|
||||||
destPaths = append(destPaths, path+"/")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
d, err := locateDevice(volumes, destPaths, options.Timeout)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return moveFile(tmppath, d+"/flash.hex")
|
|
||||||
}
|
|
||||||
|
|
||||||
func locateDevice(volumes, paths []string, timeout time.Duration) (string, error) {
|
|
||||||
var d []string
|
|
||||||
var err error
|
|
||||||
for start := time.Now(); time.Since(start) < timeout; {
|
|
||||||
for _, path := range paths {
|
|
||||||
d, err = filepath.Glob(path)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if d != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if d != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(500 * time.Millisecond)
|
time.Sleep(500 * time.Millisecond)
|
||||||
}
|
}
|
||||||
if d == nil {
|
return errors.New("unable to locate any volume: [" + strings.Join(volumes, ",") + "]")
|
||||||
return "", errors.New("unable to locate any volume: [" + strings.Join(volumes, ",") + "]")
|
|
||||||
}
|
|
||||||
return d[0], nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func windowsFindUSBDrive(volume string, options *compileopts.Options) (string, error) {
|
type mountPoint struct {
|
||||||
cmd := executeCommand(options, "wmic",
|
name string
|
||||||
"PATH", "Win32_LogicalDisk", "WHERE", "VolumeName = '"+volume+"'",
|
path string
|
||||||
"get", "DeviceID,VolumeName,FileSystem,DriveType")
|
}
|
||||||
|
|
||||||
var out bytes.Buffer
|
// Find all the mount points on the system that use the FAT filesystem.
|
||||||
cmd.Stdout = &out
|
func findFATMounts(options *compileopts.Options) ([]mountPoint, error) {
|
||||||
err := cmd.Run()
|
var points []mountPoint
|
||||||
if err != nil {
|
switch runtime.GOOS {
|
||||||
return "", err
|
case "darwin":
|
||||||
}
|
list, err := os.ReadDir("/Volumes")
|
||||||
|
if err != nil {
|
||||||
for _, line := range strings.Split(out.String(), "\n") {
|
return nil, fmt.Errorf("could not list mount points: %w", err)
|
||||||
words := strings.Fields(line)
|
|
||||||
if len(words) >= 3 {
|
|
||||||
if words[1] == "2" && words[2] == "FAT" {
|
|
||||||
return words[0], nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
for _, elem := range list {
|
||||||
|
// TODO: find a way to check for the filesystem type.
|
||||||
|
// (Only return FAT filesystems).
|
||||||
|
points = append(points, mountPoint{
|
||||||
|
name: elem.Name(),
|
||||||
|
path: filepath.Join("/Volumes", elem.Name()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
sort.Slice(points, func(i, j int) bool {
|
||||||
|
return points[i].path < points[j].name
|
||||||
|
})
|
||||||
|
return points, nil
|
||||||
|
case "linux":
|
||||||
|
tab, err := os.ReadFile("/proc/mounts") // symlink to /proc/self/mounts on my system
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not list mount points: %w", err)
|
||||||
|
}
|
||||||
|
for _, line := range strings.Split(string(tab), "\n") {
|
||||||
|
fields := strings.Fields(line)
|
||||||
|
if len(fields) <= 2 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fstype := fields[2]
|
||||||
|
if fstype != "vfat" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
points = append(points, mountPoint{
|
||||||
|
name: filepath.Base(fields[1]),
|
||||||
|
path: fields[1],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return points, nil
|
||||||
|
case "windows":
|
||||||
|
// Obtain a list of all currently mounted volumes.
|
||||||
|
cmd := executeCommand(options, "wmic",
|
||||||
|
"PATH", "Win32_LogicalDisk",
|
||||||
|
"get", "DeviceID,VolumeName,FileSystem,DriveType")
|
||||||
|
var out bytes.Buffer
|
||||||
|
cmd.Stdout = &out
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("could not list mount points: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract data to convert to a []mountPoint slice.
|
||||||
|
for _, line := range strings.Split(out.String(), "\n") {
|
||||||
|
words := strings.Fields(line)
|
||||||
|
if len(words) < 3 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if words[1] != "2" || words[2] != "FAT" {
|
||||||
|
// - DriveType 2 is removable (which we're looking for).
|
||||||
|
// - We only want to return FAT filesystems.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
points = append(points, mountPoint{
|
||||||
|
name: words[3],
|
||||||
|
path: words[0],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return points, nil
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown GOOS for listing mount points: %s", runtime.GOOS)
|
||||||
}
|
}
|
||||||
return "", errors.New("unable to locate a USB device to be flashed")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getDefaultPort returns the default serial port depending on the operating system.
|
// getDefaultPort returns the default serial port depending on the operating system.
|
||||||
@@ -1777,15 +1796,17 @@ func main() {
|
|||||||
}
|
}
|
||||||
if flagJSON {
|
if flagJSON {
|
||||||
json, _ := json.MarshalIndent(struct {
|
json, _ := json.MarshalIndent(struct {
|
||||||
GOROOT string `json:"goroot"`
|
Target *compileopts.TargetSpec `json:"target"`
|
||||||
GOOS string `json:"goos"`
|
GOROOT string `json:"goroot"`
|
||||||
GOARCH string `json:"goarch"`
|
GOOS string `json:"goos"`
|
||||||
GOARM string `json:"goarm"`
|
GOARCH string `json:"goarch"`
|
||||||
BuildTags []string `json:"build_tags"`
|
GOARM string `json:"goarm"`
|
||||||
GC string `json:"garbage_collector"`
|
BuildTags []string `json:"build_tags"`
|
||||||
Scheduler string `json:"scheduler"`
|
GC string `json:"garbage_collector"`
|
||||||
LLVMTriple string `json:"llvm_triple"`
|
Scheduler string `json:"scheduler"`
|
||||||
|
LLVMTriple string `json:"llvm_triple"`
|
||||||
}{
|
}{
|
||||||
|
Target: config.Target,
|
||||||
GOROOT: cachedGOROOT,
|
GOROOT: cachedGOROOT,
|
||||||
GOOS: config.GOOS(),
|
GOOS: config.GOOS(),
|
||||||
GOARCH: config.GOARCH(),
|
GOARCH: config.GOARCH(),
|
||||||
@@ -1852,7 +1873,7 @@ func main() {
|
|||||||
usage(command)
|
usage(command)
|
||||||
case "version":
|
case "version":
|
||||||
goversion := "<unknown>"
|
goversion := "<unknown>"
|
||||||
if s, err := goenv.GorootVersionString(goenv.Get("GOROOT")); err == nil {
|
if s, err := goenv.GorootVersionString(); err == nil {
|
||||||
goversion = s
|
goversion = s
|
||||||
}
|
}
|
||||||
version := goenv.Version
|
version := goenv.Version
|
||||||
|
|||||||
+24
-2
@@ -34,6 +34,16 @@ var supportedLinuxArches = map[string]string{
|
|||||||
"X86Linux": "linux/386",
|
"X86Linux": "linux/386",
|
||||||
"ARMLinux": "linux/arm/6",
|
"ARMLinux": "linux/arm/6",
|
||||||
"ARM64Linux": "linux/arm64",
|
"ARM64Linux": "linux/arm64",
|
||||||
|
"WASIp1": "wasip1/wasm",
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
major, _, _ := goenv.GetGorootVersion()
|
||||||
|
if major < 21 {
|
||||||
|
// Go 1.20 backwards compatibility.
|
||||||
|
// Should be removed once we drop support for Go 1.20.
|
||||||
|
delete(supportedLinuxArches, "WASIp1")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var sema = make(chan struct{}, runtime.NumCPU())
|
var sema = make(chan struct{}, runtime.NumCPU())
|
||||||
@@ -71,6 +81,16 @@ func TestBuild(t *testing.T) {
|
|||||||
"zeroalloc.go",
|
"zeroalloc.go",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go 1.21 made some changes to the language, which we can only test when
|
||||||
|
// we're actually on Go 1.21.
|
||||||
|
_, minor, err := goenv.GetGorootVersion()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("could not get version:", minor)
|
||||||
|
}
|
||||||
|
if minor >= 21 {
|
||||||
|
tests = append(tests, "go1.21.go")
|
||||||
|
}
|
||||||
|
|
||||||
if *testTarget != "" {
|
if *testTarget != "" {
|
||||||
// This makes it possible to run one specific test (instead of all),
|
// This makes it possible to run one specific test (instead of all),
|
||||||
// which is especially useful to quickly check whether some changes
|
// which is especially useful to quickly check whether some changes
|
||||||
@@ -166,6 +186,8 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
|||||||
t.Fatal("failed to load target spec:", err)
|
t.Fatal("failed to load target spec:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isWebAssembly := options.Target == "wasi" || options.Target == "wasm" || (options.Target == "" && options.GOARCH == "wasm")
|
||||||
|
|
||||||
for _, name := range tests {
|
for _, name := range tests {
|
||||||
if options.GOOS == "linux" && (options.GOARCH == "arm" || options.GOARCH == "386") {
|
if options.GOOS == "linux" && (options.GOARCH == "arm" || options.GOARCH == "386") {
|
||||||
switch name {
|
switch name {
|
||||||
@@ -216,7 +238,7 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
|||||||
runTest("env.go", options, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
|
runTest("env.go", options, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if options.Target == "wasi" || options.Target == "wasm" {
|
if isWebAssembly {
|
||||||
t.Run("alias.go-scheduler-none", func(t *testing.T) {
|
t.Run("alias.go-scheduler-none", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
options := compileopts.Options(options)
|
options := compileopts.Options(options)
|
||||||
@@ -236,7 +258,7 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
|||||||
runTest("rand.go", options, t, nil, nil)
|
runTest("rand.go", options, t, nil, nil)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if options.Target != "wasi" && options.Target != "wasm" {
|
if !isWebAssembly {
|
||||||
// The recover() builtin isn't supported yet on WebAssembly and Windows.
|
// The recover() builtin isn't supported yet on WebAssembly and Windows.
|
||||||
t.Run("recover.go", func(t *testing.T) {
|
t.Run("recover.go", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
//go:build arduino
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "machine"
|
||||||
|
|
||||||
|
const (
|
||||||
|
button = machine.D2
|
||||||
|
buttonMode = machine.PinInputPullup
|
||||||
|
buttonPinChange = machine.PinRising
|
||||||
|
)
|
||||||
@@ -5,6 +5,7 @@ package main
|
|||||||
import "machine"
|
import "machine"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
button = machine.BUTTON
|
||||||
buttonMode = machine.PinInputPulldown
|
buttonMode = machine.PinInputPulldown
|
||||||
buttonPinChange = machine.PinFalling
|
buttonPinChange = machine.PinFalling
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package main
|
|||||||
import "machine"
|
import "machine"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
button = machine.BUTTON
|
||||||
buttonMode = machine.PinInputPullup
|
buttonMode = machine.PinInputPullup
|
||||||
buttonPinChange = machine.PinRising
|
buttonPinChange = machine.PinRising
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,18 +8,14 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"machine"
|
"machine"
|
||||||
"runtime/volatile"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
button = machine.BUTTON
|
led = machine.LED
|
||||||
led = machine.LED
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var lightLed volatile.Register8
|
|
||||||
lightLed.Set(0)
|
|
||||||
|
|
||||||
// Configure the LED, defaulting to on (usually setting the pin to low will
|
// Configure the LED, defaulting to on (usually setting the pin to low will
|
||||||
// turn the LED on).
|
// turn the LED on).
|
||||||
@@ -33,13 +29,7 @@ func main() {
|
|||||||
|
|
||||||
// Set an interrupt on this pin.
|
// Set an interrupt on this pin.
|
||||||
err := button.SetInterrupt(buttonPinChange, func(machine.Pin) {
|
err := button.SetInterrupt(buttonPinChange, func(machine.Pin) {
|
||||||
if lightLed.Get() != 0 {
|
led.Set(!led.Get())
|
||||||
lightLed.Set(0)
|
|
||||||
led.Low()
|
|
||||||
} else {
|
|
||||||
lightLed.Set(1)
|
|
||||||
led.High()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
println("could not configure pin interrupt:", err.Error())
|
println("could not configure pin interrupt:", err.Error())
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package main
|
|||||||
import "machine"
|
import "machine"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
button = machine.BUTTON
|
||||||
buttonMode = machine.PinInputPulldown
|
buttonMode = machine.PinInputPulldown
|
||||||
buttonPinChange = machine.PinRising | machine.PinFalling
|
buttonPinChange = machine.PinRising | machine.PinFalling
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ package main
|
|||||||
import "machine"
|
import "machine"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
button = machine.BUTTON
|
||||||
buttonMode = machine.PinInput
|
buttonMode = machine.PinInput
|
||||||
buttonPinChange = machine.PinFalling
|
buttonPinChange = machine.PinFalling
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
// This example demonstrates how to set the system time.
|
||||||
|
//
|
||||||
|
// Usually, boards don't keep time on power cycles and restarts, it resets to Unix epoch.
|
||||||
|
// The system time can be set by calling runtime.AdjustTimeOffset().
|
||||||
|
//
|
||||||
|
// Possible time sources: an external RTC clock or network (WiFi access point or NTP server)
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
const myTime = "2006-01-02T15:04:05Z" // this is an example time you source somewhere
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
// measure how many nanoseconds the internal clock is behind
|
||||||
|
timeOfMeasurement := time.Now()
|
||||||
|
actualTime, _ := time.Parse(time.RFC3339, myTime)
|
||||||
|
offset := actualTime.Sub(timeOfMeasurement)
|
||||||
|
|
||||||
|
// adjust internal clock by adding the offset to the internal clock
|
||||||
|
runtime.AdjustTimeOffset(int64(offset))
|
||||||
|
|
||||||
|
for {
|
||||||
|
fmt.Printf("%v\r\n", time.Now().Format(time.RFC3339))
|
||||||
|
time.Sleep(5 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"machine"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
//sleep for 2 secs for console
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
|
||||||
|
config := machine.WatchdogConfig{
|
||||||
|
TimeoutMillis: 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
println("configuring watchdog for max 1 second updates")
|
||||||
|
machine.Watchdog.Configure(config)
|
||||||
|
|
||||||
|
// From this point the watchdog is running and Update must be
|
||||||
|
// called periodically, per the config
|
||||||
|
machine.Watchdog.Start()
|
||||||
|
|
||||||
|
// This loop should complete because watchdog update is called
|
||||||
|
// every 100ms.
|
||||||
|
start := time.Now()
|
||||||
|
println("updating watchdog for 3 seconds")
|
||||||
|
for i := 0; i < 30; i++ {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
machine.Watchdog.Update()
|
||||||
|
fmt.Printf("alive @ %v\n", time.Now().Sub(start))
|
||||||
|
}
|
||||||
|
|
||||||
|
// This loop should cause a watchdog reset after 1s since
|
||||||
|
// there is no update call.
|
||||||
|
start = time.Now()
|
||||||
|
println("entering tight loop")
|
||||||
|
for {
|
||||||
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
fmt.Printf("alive @ %v\n", time.Now().Sub(start))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -251,3 +251,13 @@ func IndexRabinKarp(s, substr string) int {
|
|||||||
}
|
}
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeNoZero makes a slice of length and capacity n without zeroing the bytes.
|
||||||
|
// It is the caller's responsibility to ensure uninitialized bytes
|
||||||
|
// do not leak to the end user.
|
||||||
|
func MakeNoZero(n int) []byte {
|
||||||
|
// Note: this does zero the buffer even though that's not necessary.
|
||||||
|
// For performance reasons we might want to change this (similar to the
|
||||||
|
// malloc function implemented in the runtime).
|
||||||
|
return make([]byte, n)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,111 @@
|
|||||||
|
//go:build ae_rp2040
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/rp"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GPIO pins
|
||||||
|
const (
|
||||||
|
GP0 Pin = GPIO0
|
||||||
|
GP1 Pin = GPIO1
|
||||||
|
GP2 Pin = GPIO2
|
||||||
|
GP3 Pin = GPIO3
|
||||||
|
GP4 Pin = GPIO4
|
||||||
|
GP5 Pin = GPIO5
|
||||||
|
GP6 Pin = GPIO6
|
||||||
|
GP7 Pin = GPIO7
|
||||||
|
GP8 Pin = GPIO8
|
||||||
|
GP9 Pin = GPIO9
|
||||||
|
GP10 Pin = GPIO10
|
||||||
|
GP11 Pin = GPIO11
|
||||||
|
GP12 Pin = GPIO12
|
||||||
|
GP13 Pin = GPIO13
|
||||||
|
GP14 Pin = GPIO14
|
||||||
|
GP15 Pin = GPIO15
|
||||||
|
GP16 Pin = GPIO16
|
||||||
|
GP17 Pin = GPIO17
|
||||||
|
GP18 Pin = GPIO18
|
||||||
|
GP19 Pin = GPIO19
|
||||||
|
GP20 Pin = GPIO20
|
||||||
|
GP21 Pin = GPIO21
|
||||||
|
GP22 Pin = GPIO22
|
||||||
|
GP26 Pin = GPIO26
|
||||||
|
GP27 Pin = GPIO27
|
||||||
|
GP28 Pin = GPIO28
|
||||||
|
GP29 Pin = GPIO29
|
||||||
|
|
||||||
|
// Onboard crystal oscillator frequency, in MHz.
|
||||||
|
xoscFreq = 12 // MHz
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C Default pins on Raspberry Pico.
|
||||||
|
const (
|
||||||
|
I2C0_SDA_PIN = GP4
|
||||||
|
I2C0_SCL_PIN = GP5
|
||||||
|
|
||||||
|
I2C1_SDA_PIN = GP2
|
||||||
|
I2C1_SCL_PIN = GP3
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI default pins
|
||||||
|
const (
|
||||||
|
// Default Serial Clock Bus 0 for SPI communications
|
||||||
|
SPI0_SCK_PIN = GPIO18
|
||||||
|
// Default Serial Out Bus 0 for SPI communications
|
||||||
|
SPI0_SDO_PIN = GPIO19 // Tx
|
||||||
|
// Default Serial In Bus 0 for SPI communications
|
||||||
|
SPI0_SDI_PIN = GPIO16 // Rx
|
||||||
|
|
||||||
|
// Default Serial Clock Bus 1 for SPI communications
|
||||||
|
SPI1_SCK_PIN = GPIO10
|
||||||
|
// Default Serial Out Bus 1 for SPI communications
|
||||||
|
SPI1_SDO_PIN = GPIO11 // Tx
|
||||||
|
// Default Serial In Bus 1 for SPI communications
|
||||||
|
SPI1_SDI_PIN = GPIO12 // Rx
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART pins
|
||||||
|
const (
|
||||||
|
UART0_TX_PIN = GPIO0
|
||||||
|
UART0_RX_PIN = GPIO1
|
||||||
|
UART1_TX_PIN = GPIO8
|
||||||
|
UART1_RX_PIN = GPIO9
|
||||||
|
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 = "AE-RP2040"
|
||||||
|
usb_STRING_MANUFACTURER = "AKIZUKI DENSHI"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
usb_VID uint16 = 0x2E8A
|
||||||
|
usb_PID uint16 = 0x000A
|
||||||
|
)
|
||||||
@@ -16,6 +16,7 @@ const (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
SWITCH = GPIO0
|
SWITCH = GPIO0
|
||||||
|
BUTTON = GPIO0
|
||||||
|
|
||||||
KEY1 = GPIO1
|
KEY1 = GPIO1
|
||||||
KEY2 = GPIO2
|
KEY2 = GPIO2
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ func (i2c *I2C) stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// writeByte writes a single byte to the I2C bus.
|
// writeByte writes a single byte to the I2C bus.
|
||||||
func (i2c *I2C) writeByte(data byte) {
|
func (i2c *I2C) writeByte(data byte) error {
|
||||||
// Write data to register.
|
// Write data to register.
|
||||||
avr.TWDR.Set(data)
|
avr.TWDR.Set(data)
|
||||||
|
|
||||||
@@ -107,6 +107,7 @@ func (i2c *I2C) writeByte(data byte) {
|
|||||||
// Wait till data is transmitted.
|
// Wait till data is transmitted.
|
||||||
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
|
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// readByte reads a single byte from the I2C bus.
|
// readByte reads a single byte from the I2C bus.
|
||||||
@@ -190,7 +191,7 @@ func (uart *UART) handleInterrupt(intr interrupt.Interrupt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (uart *UART) WriteByte(c byte) error {
|
func (uart *UART) writeByte(c byte) error {
|
||||||
// Wait until UART buffer is not busy.
|
// Wait until UART buffer is not busy.
|
||||||
for !uart.statusRegA.HasBits(avr.UCSR0A_UDRE0) {
|
for !uart.statusRegA.HasBits(avr.UCSR0A_UDRE0) {
|
||||||
}
|
}
|
||||||
@@ -198,6 +199,8 @@ func (uart *UART) WriteByte(c byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|
||||||
// SPIConfig is used to store config info for SPI.
|
// SPIConfig is used to store config info for SPI.
|
||||||
type SPIConfig struct {
|
type SPIConfig struct {
|
||||||
Frequency uint32
|
Frequency uint32
|
||||||
|
|||||||
@@ -466,3 +466,107 @@ var SPI0 = SPI{
|
|||||||
sdo: PB3,
|
sdo: PB3,
|
||||||
sdi: PB4,
|
sdi: PB4,
|
||||||
cs: PB2}
|
cs: PB2}
|
||||||
|
|
||||||
|
// Pin Change Interrupts
|
||||||
|
type PinChange uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
PinRising PinChange = 1 << iota
|
||||||
|
PinFalling
|
||||||
|
PinToggle = PinRising | PinFalling
|
||||||
|
)
|
||||||
|
|
||||||
|
func (pin Pin) SetInterrupt(pinChange PinChange, callback func(Pin)) (err error) {
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case pin >= PB0 && pin <= PB7:
|
||||||
|
// PCMSK0 - PCINT0-7
|
||||||
|
pinStates[0] = avr.PINB.Get()
|
||||||
|
pinIndex := pin - PB0
|
||||||
|
if pinChange&PinRising > 0 {
|
||||||
|
pinCallbacks[0][pinIndex][0] = callback
|
||||||
|
}
|
||||||
|
if pinChange&PinFalling > 0 {
|
||||||
|
pinCallbacks[0][pinIndex][1] = callback
|
||||||
|
}
|
||||||
|
if callback != nil {
|
||||||
|
avr.PCMSK0.SetBits(1 << pinIndex)
|
||||||
|
} else {
|
||||||
|
avr.PCMSK0.ClearBits(1 << pinIndex)
|
||||||
|
}
|
||||||
|
avr.PCICR.SetBits(avr.PCICR_PCIE0)
|
||||||
|
interrupt.New(avr.IRQ_PCINT0, handlePCINT0Interrupts)
|
||||||
|
case pin >= PC0 && pin <= PC7:
|
||||||
|
// PCMSK1 - PCINT8-14
|
||||||
|
pinStates[1] = avr.PINC.Get()
|
||||||
|
pinIndex := pin - PC0
|
||||||
|
if pinChange&PinRising > 0 {
|
||||||
|
pinCallbacks[1][pinIndex][0] = callback
|
||||||
|
}
|
||||||
|
if pinChange&PinFalling > 0 {
|
||||||
|
pinCallbacks[1][pinIndex][1] = callback
|
||||||
|
}
|
||||||
|
if callback != nil {
|
||||||
|
avr.PCMSK1.SetBits(1 << pinIndex)
|
||||||
|
} else {
|
||||||
|
avr.PCMSK1.ClearBits(1 << pinIndex)
|
||||||
|
}
|
||||||
|
avr.PCICR.SetBits(avr.PCICR_PCIE1)
|
||||||
|
interrupt.New(avr.IRQ_PCINT1, handlePCINT1Interrupts)
|
||||||
|
case pin >= PD0 && pin <= PD7:
|
||||||
|
// PCMSK2 - PCINT16-23
|
||||||
|
pinStates[2] = avr.PIND.Get()
|
||||||
|
pinIndex := pin - PD0
|
||||||
|
if pinChange&PinRising > 0 {
|
||||||
|
pinCallbacks[2][pinIndex][0] = callback
|
||||||
|
}
|
||||||
|
if pinChange&PinFalling > 0 {
|
||||||
|
pinCallbacks[2][pinIndex][1] = callback
|
||||||
|
}
|
||||||
|
if callback != nil {
|
||||||
|
avr.PCMSK2.SetBits(1 << pinIndex)
|
||||||
|
} else {
|
||||||
|
avr.PCMSK2.ClearBits(1 << pinIndex)
|
||||||
|
}
|
||||||
|
avr.PCICR.SetBits(avr.PCICR_PCIE2)
|
||||||
|
interrupt.New(avr.IRQ_PCINT2, handlePCINT2Interrupts)
|
||||||
|
default:
|
||||||
|
return ErrInvalidInputPin
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var pinCallbacks [3][8][2]func(Pin)
|
||||||
|
var pinStates [3]uint8
|
||||||
|
|
||||||
|
func handlePCINTInterrupts(intr uint8, port *volatile.Register8) {
|
||||||
|
current := port.Get()
|
||||||
|
change := pinStates[intr] ^ current
|
||||||
|
pinStates[intr] = current
|
||||||
|
for i := uint8(0); i < 8; i++ {
|
||||||
|
if (change>>i)&0x01 != 0x01 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pin := Pin(intr*8 + i)
|
||||||
|
value := pin.Get()
|
||||||
|
if value && pinCallbacks[intr][i][0] != nil {
|
||||||
|
pinCallbacks[intr][i][0](pin)
|
||||||
|
}
|
||||||
|
if !value && pinCallbacks[intr][i][1] != nil {
|
||||||
|
pinCallbacks[intr][i][1](pin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePCINT0Interrupts(intr interrupt.Interrupt) {
|
||||||
|
handlePCINTInterrupts(0, avr.PINB)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePCINT1Interrupts(intr interrupt.Interrupt) {
|
||||||
|
handlePCINTInterrupts(1, avr.PINC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePCINT2Interrupts(intr interrupt.Interrupt) {
|
||||||
|
handlePCINTInterrupts(2, avr.PIND)
|
||||||
|
}
|
||||||
|
|||||||
@@ -626,7 +626,7 @@ func (uart *UART) SetBaudRate(br uint32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (uart *UART) WriteByte(c byte) error {
|
func (uart *UART) writeByte(c byte) error {
|
||||||
// wait until ready to receive
|
// wait until ready to receive
|
||||||
for !uart.Bus.INTFLAG.HasBits(sam.SERCOM_USART_INTFLAG_DRE) {
|
for !uart.Bus.INTFLAG.HasBits(sam.SERCOM_USART_INTFLAG_DRE) {
|
||||||
}
|
}
|
||||||
@@ -634,6 +634,8 @@ func (uart *UART) WriteByte(c byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|
||||||
// handleInterrupt should be called from the appropriate interrupt handler for
|
// handleInterrupt should be called from the appropriate interrupt handler for
|
||||||
// this UART instance.
|
// this UART instance.
|
||||||
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
||||||
|
|||||||
@@ -1114,7 +1114,7 @@ func (uart *UART) SetBaudRate(br uint32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (uart *UART) WriteByte(c byte) error {
|
func (uart *UART) writeByte(c byte) error {
|
||||||
// wait until ready to receive
|
// wait until ready to receive
|
||||||
for !uart.Bus.INTFLAG.HasBits(sam.SERCOM_USART_INT_INTFLAG_DRE) {
|
for !uart.Bus.INTFLAG.HasBits(sam.SERCOM_USART_INT_INTFLAG_DRE) {
|
||||||
}
|
}
|
||||||
@@ -1122,6 +1122,8 @@ func (uart *UART) WriteByte(c byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|
||||||
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
||||||
// should reset IRQ
|
// should reset IRQ
|
||||||
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
|
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
|
||||||
@@ -1162,7 +1164,7 @@ const (
|
|||||||
wireCmdStop = 3
|
wireCmdStop = 3
|
||||||
)
|
)
|
||||||
|
|
||||||
const i2cTimeout = 1000
|
const i2cTimeout = 28000 // about 210us
|
||||||
|
|
||||||
// Configure is intended to setup the I2C interface.
|
// Configure is intended to setup the I2C interface.
|
||||||
func (i2c *I2C) Configure(config I2CConfig) error {
|
func (i2c *I2C) Configure(config I2CConfig) error {
|
||||||
@@ -2297,3 +2299,52 @@ func checkFlashError() error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Watchdog provides access to the hardware watchdog available
|
||||||
|
// in the SAMD51.
|
||||||
|
var Watchdog = &watchdogImpl{}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// WatchdogMaxTimeout in milliseconds (16s)
|
||||||
|
WatchdogMaxTimeout = (16384 * 1000) / 1024 // CYC16384/1024kHz
|
||||||
|
)
|
||||||
|
|
||||||
|
type watchdogImpl struct{}
|
||||||
|
|
||||||
|
// Configure the watchdog.
|
||||||
|
//
|
||||||
|
// This method should not be called after the watchdog is started and on
|
||||||
|
// some platforms attempting to reconfigure after starting the watchdog
|
||||||
|
// is explicitly forbidden / will not work.
|
||||||
|
func (wd *watchdogImpl) Configure(config WatchdogConfig) error {
|
||||||
|
// 1.024kHz clock
|
||||||
|
cycles := int((int64(config.TimeoutMillis) * 1024) / 1000)
|
||||||
|
|
||||||
|
// period is expressed as a power-of-two, starting at 8 / 1024ths of a second
|
||||||
|
period := uint8(0)
|
||||||
|
cfgCycles := 8
|
||||||
|
for cfgCycles < cycles {
|
||||||
|
period++
|
||||||
|
cfgCycles <<= 1
|
||||||
|
|
||||||
|
if period >= 0xB {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sam.WDT.CONFIG.Set(period << sam.WDT_CONFIG_PER_Pos)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts the watchdog.
|
||||||
|
func (wd *watchdogImpl) Start() error {
|
||||||
|
sam.WDT.CTRLA.SetBits(sam.WDT_CTRLA_ENABLE)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the watchdog, indicating that `source` is healthy.
|
||||||
|
func (wd *watchdogImpl) Update() {
|
||||||
|
// 0xA5 = magic value (see datasheet)
|
||||||
|
sam.WDT.CLEAR.Set(0xA5)
|
||||||
|
}
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ func (uart *UART) Configure(config UARTConfig) {
|
|||||||
uart.Bus.CLKDIV.Set(peripheralClock / config.BaudRate)
|
uart.Bus.CLKDIV.Set(peripheralClock / config.BaudRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uart *UART) WriteByte(b byte) error {
|
func (uart *UART) writeByte(b byte) error {
|
||||||
for (uart.Bus.STATUS.Get()>>16)&0xff >= 128 {
|
for (uart.Bus.STATUS.Get()>>16)&0xff >= 128 {
|
||||||
// Read UART_TXFIFO_CNT from the status register, which indicates how
|
// Read UART_TXFIFO_CNT from the status register, which indicates how
|
||||||
// many bytes there are in the transmit buffer. Wait until there are
|
// many bytes there are in the transmit buffer. Wait until there are
|
||||||
@@ -324,6 +324,8 @@ func (uart *UART) WriteByte(b byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|
||||||
// Serial Peripheral Interface on the ESP32.
|
// Serial Peripheral Interface on the ESP32.
|
||||||
type SPI struct {
|
type SPI struct {
|
||||||
Bus *esp.SPI_Type
|
Bus *esp.SPI_Type
|
||||||
|
|||||||
@@ -493,7 +493,7 @@ func (uart *UART) enableReceiver() {
|
|||||||
uart.Bus.SetINT_ENA_RXFIFO_OVF_INT_ENA(1)
|
uart.Bus.SetINT_ENA_RXFIFO_OVF_INT_ENA(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uart *UART) WriteByte(b byte) error {
|
func (uart *UART) writeByte(b byte) error {
|
||||||
for (uart.Bus.STATUS.Get()&esp.UART_STATUS_TXFIFO_CNT_Msk)>>esp.UART_STATUS_TXFIFO_CNT_Pos >= 128 {
|
for (uart.Bus.STATUS.Get()&esp.UART_STATUS_TXFIFO_CNT_Msk)>>esp.UART_STATUS_TXFIFO_CNT_Pos >= 128 {
|
||||||
// Read UART_TXFIFO_CNT from the status register, which indicates how
|
// Read UART_TXFIFO_CNT from the status register, which indicates how
|
||||||
// many bytes there are in the transmit buffer. Wait until there are
|
// many bytes there are in the transmit buffer. Wait until there are
|
||||||
@@ -502,3 +502,5 @@ func (uart *UART) WriteByte(b byte) error {
|
|||||||
uart.Bus.FIFO.Set(uint32(b))
|
uart.Bus.FIFO.Set(uint32(b))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|||||||
@@ -181,12 +181,14 @@ func (uart *UART) Configure(config UARTConfig) {
|
|||||||
esp.UART0.UART_CLKDIV.Set(CPUFrequency() / config.BaudRate)
|
esp.UART0.UART_CLKDIV.Set(CPUFrequency() / config.BaudRate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a single byte to the output buffer. Note that the hardware
|
// writeByte writes a single byte to the output buffer. Note that the hardware
|
||||||
// includes a buffer of 128 bytes which will be used first.
|
// includes a buffer of 128 bytes which will be used first.
|
||||||
func (uart *UART) WriteByte(c byte) error {
|
func (uart *UART) writeByte(c byte) error {
|
||||||
for (esp.UART0.UART_STATUS.Get()>>16)&0xff >= 128 {
|
for (esp.UART0.UART_STATUS.Get()>>16)&0xff >= 128 {
|
||||||
// Wait until the TX buffer has room.
|
// Wait until the TX buffer has room.
|
||||||
}
|
}
|
||||||
esp.UART0.UART_FIFO.Set(uint32(c))
|
esp.UART0.UART_FIFO.Set(uint32(c))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|||||||
@@ -111,13 +111,16 @@ func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
|||||||
uart.Receive(c)
|
uart.Receive(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uart *UART) WriteByte(c byte) {
|
func (uart *UART) writeByte(c byte) error {
|
||||||
for sifive.UART0.TXDATA.Get()&sifive.UART_TXDATA_FULL != 0 {
|
for sifive.UART0.TXDATA.Get()&sifive.UART_TXDATA_FULL != 0 {
|
||||||
}
|
}
|
||||||
|
|
||||||
sifive.UART0.TXDATA.Set(uint32(c))
|
sifive.UART0.TXDATA.Set(uint32(c))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|
||||||
// SPI on the FE310. The normal SPI0 is actually a quad-SPI meant for flash, so it is best
|
// SPI on the FE310. The normal SPI0 is actually a quad-SPI meant for flash, so it is best
|
||||||
// to use SPI1 or SPI2 port for most applications.
|
// to use SPI1 or SPI2 port for most applications.
|
||||||
type SPI struct {
|
type SPI struct {
|
||||||
|
|||||||
@@ -392,13 +392,16 @@ func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
|||||||
uart.Receive(c)
|
uart.Receive(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uart *UART) WriteByte(c byte) {
|
func (uart *UART) writeByte(c byte) error {
|
||||||
for uart.Bus.TXDATA.Get()&kendryte.UARTHS_TXDATA_FULL != 0 {
|
for uart.Bus.TXDATA.Get()&kendryte.UARTHS_TXDATA_FULL != 0 {
|
||||||
}
|
}
|
||||||
|
|
||||||
uart.Bus.TXDATA.Set(uint32(c))
|
uart.Bus.TXDATA.Set(uint32(c))
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|
||||||
type SPI struct {
|
type SPI struct {
|
||||||
Bus *kendryte.SPI_Type
|
Bus *kendryte.SPI_Type
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ func (uart *UART) Sync() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a single byte of data to the UART interface.
|
// WriteByte writes a single byte of data to the UART interface.
|
||||||
func (uart *UART) WriteByte(c byte) error {
|
func (uart *UART) writeByte(c byte) error {
|
||||||
uart.startTransmitting()
|
uart.startTransmitting()
|
||||||
for !uart.txBuffer.Put(c) {
|
for !uart.txBuffer.Put(c) {
|
||||||
}
|
}
|
||||||
@@ -181,6 +181,8 @@ func (uart *UART) WriteByte(c byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|
||||||
// getBaudRateDivisor finds the greatest over-sampling factor (4..32) and
|
// getBaudRateDivisor finds the greatest over-sampling factor (4..32) and
|
||||||
// corresponding baud rate divisor (1..8191) that best partition a given baud
|
// corresponding baud rate divisor (1..8191) that best partition a given baud
|
||||||
// rate into equal intervals.
|
// rate into equal intervals.
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ func (uart *UART) SetBaudRate(br uint32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (uart *UART) WriteByte(c byte) error {
|
func (uart *UART) writeByte(c byte) error {
|
||||||
nrf.UART0.EVENTS_TXDRDY.Set(0)
|
nrf.UART0.EVENTS_TXDRDY.Set(0)
|
||||||
nrf.UART0.TXD.Set(uint32(c))
|
nrf.UART0.TXD.Set(uint32(c))
|
||||||
for nrf.UART0.EVENTS_TXDRDY.Get() == 0 {
|
for nrf.UART0.EVENTS_TXDRDY.Get() == 0 {
|
||||||
@@ -194,6 +194,8 @@ func (uart *UART) WriteByte(c byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|
||||||
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
||||||
if nrf.UART0.EVENTS_RXDRDY.Get() != 0 {
|
if nrf.UART0.EVENTS_RXDRDY.Get() != 0 {
|
||||||
uart.Receive(byte(nrf.UART0.RXD.Get()))
|
uart.Receive(byte(nrf.UART0.RXD.Get()))
|
||||||
@@ -201,6 +203,8 @@ func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const i2cTimeout = 0xffff // this is around 29ms on a nrf52
|
||||||
|
|
||||||
// I2CConfig is used to store config info for I2C.
|
// I2CConfig is used to store config info for I2C.
|
||||||
type I2CConfig struct {
|
type I2CConfig struct {
|
||||||
Frequency uint32
|
Frequency uint32
|
||||||
@@ -259,11 +263,17 @@ func (i2c *I2C) Configure(config I2CConfig) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// signalStop sends a stop signal to the I2C peripheral and waits for confirmation.
|
// signalStop sends a stop signal to the I2C peripheral and waits for confirmation.
|
||||||
func (i2c *I2C) signalStop() {
|
func (i2c *I2C) signalStop() error {
|
||||||
|
tries := 0
|
||||||
i2c.Bus.TASKS_STOP.Set(1)
|
i2c.Bus.TASKS_STOP.Set(1)
|
||||||
for i2c.Bus.EVENTS_STOPPED.Get() == 0 {
|
for i2c.Bus.EVENTS_STOPPED.Get() == 0 {
|
||||||
|
tries++
|
||||||
|
if tries >= i2cTimeout {
|
||||||
|
return errI2CSignalStopTimeout
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i2c.Bus.EVENTS_STOPPED.Set(0)
|
i2c.Bus.EVENTS_STOPPED.Set(0)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var rngStarted = false
|
var rngStarted = false
|
||||||
|
|||||||
@@ -214,3 +214,46 @@ func twisError(val uint32) error {
|
|||||||
|
|
||||||
return errI2CBusError
|
return errI2CBusError
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
Watchdog = &watchdogImpl{}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// WatchdogMaxTimeout in milliseconds (approx 36h)
|
||||||
|
WatchdogMaxTimeout = (0xffffffff * 1000) / 32768
|
||||||
|
)
|
||||||
|
|
||||||
|
type watchdogImpl struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the watchdog.
|
||||||
|
//
|
||||||
|
// This method should not be called after the watchdog is started and on
|
||||||
|
// some platforms attempting to reconfigure after starting the watchdog
|
||||||
|
// is explicitly forbidden / will not work.
|
||||||
|
func (wd *watchdogImpl) Configure(config WatchdogConfig) error {
|
||||||
|
// 32.768kHz counter
|
||||||
|
crv := int32((int64(config.TimeoutMillis) * 32768) / 1000)
|
||||||
|
nrf.WDT.CRV.Set(uint32(crv))
|
||||||
|
|
||||||
|
// One source
|
||||||
|
nrf.WDT.RREN.Set(0x1)
|
||||||
|
|
||||||
|
// Run during sleep
|
||||||
|
nrf.WDT.CONFIG.Set(nrf.WDT_CONFIG_SLEEP_Run)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts the watchdog.
|
||||||
|
func (wd *watchdogImpl) Start() error {
|
||||||
|
nrf.WDT.TASKS_START.Set(nrf.WDT_TASKS_START_TASKS_START)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the watchdog, indicating that `source` is healthy.
|
||||||
|
func (wd *watchdogImpl) Update() {
|
||||||
|
// 0x6E524635 = magic value from datasheet
|
||||||
|
nrf.WDT.RR[0].Set(0x6E524635)
|
||||||
|
}
|
||||||
|
|||||||
@@ -288,24 +288,27 @@ func (spi SPI) Tx(w, r []byte) error {
|
|||||||
// supported.
|
// supported.
|
||||||
for len(r) != 0 || len(w) != 0 {
|
for len(r) != 0 || len(w) != 0 {
|
||||||
// Prepare the SPI transfer: set the DMA pointers and lengths.
|
// Prepare the SPI transfer: set the DMA pointers and lengths.
|
||||||
if len(r) != 0 {
|
// read buffer
|
||||||
|
nr := uint32(len(r))
|
||||||
|
if nr > 0 {
|
||||||
|
if nr > 255 {
|
||||||
|
nr = 255
|
||||||
|
}
|
||||||
spi.Bus.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&r[0]))))
|
spi.Bus.RXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&r[0]))))
|
||||||
n := uint32(len(r))
|
r = r[nr:]
|
||||||
if n > 255 {
|
|
||||||
n = 255
|
|
||||||
}
|
|
||||||
spi.Bus.RXD.MAXCNT.Set(n)
|
|
||||||
r = r[n:]
|
|
||||||
}
|
}
|
||||||
if len(w) != 0 {
|
spi.Bus.RXD.MAXCNT.Set(nr)
|
||||||
|
|
||||||
|
// write buffer
|
||||||
|
nw := uint32(len(w))
|
||||||
|
if nw > 0 {
|
||||||
|
if nw > 255 {
|
||||||
|
nw = 255
|
||||||
|
}
|
||||||
spi.Bus.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&w[0]))))
|
spi.Bus.TXD.PTR.Set(uint32(uintptr(unsafe.Pointer(&w[0]))))
|
||||||
n := uint32(len(w))
|
w = w[nw:]
|
||||||
if n > 255 {
|
|
||||||
n = 255
|
|
||||||
}
|
|
||||||
spi.Bus.TXD.MAXCNT.Set(n)
|
|
||||||
w = w[n:]
|
|
||||||
}
|
}
|
||||||
|
spi.Bus.TXD.MAXCNT.Set(nw)
|
||||||
|
|
||||||
// Do the transfer.
|
// Do the transfer.
|
||||||
// Note: this can be improved by not waiting until the transfer is
|
// Note: this can be improved by not waiting until the transfer is
|
||||||
|
|||||||
@@ -70,11 +70,21 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) {
|
|||||||
i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND_Disabled)
|
i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND_Disabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop explicitly when no reads were executed, stoping unconditionally would be a mistake.
|
|
||||||
// It may execute after I2C peripheral has already been stopped by the shortcut in the read block,
|
|
||||||
// so stop task will trigger first thing in a subsequent transaction, hanging it.
|
|
||||||
if len(r) == 0 {
|
if len(r) == 0 {
|
||||||
i2c.signalStop()
|
// Stop the I2C transaction after the write.
|
||||||
|
err = i2c.signalStop()
|
||||||
|
} else {
|
||||||
|
// The last byte read has already stopped the transaction, via
|
||||||
|
// TWI_SHORTS_BB_STOP. But we still need to wait until we receive the
|
||||||
|
// STOPPED event.
|
||||||
|
tries := 0
|
||||||
|
for i2c.Bus.EVENTS_STOPPED.Get() == 0 {
|
||||||
|
tries++
|
||||||
|
if tries >= i2cTimeout {
|
||||||
|
return errI2CSignalStopTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i2c.Bus.EVENTS_STOPPED.Set(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -82,12 +92,17 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) {
|
|||||||
|
|
||||||
// writeByte writes a single byte to the I2C bus and waits for confirmation.
|
// writeByte writes a single byte to the I2C bus and waits for confirmation.
|
||||||
func (i2c *I2C) writeByte(data byte) error {
|
func (i2c *I2C) writeByte(data byte) error {
|
||||||
|
tries := 0
|
||||||
i2c.Bus.TXD.Set(uint32(data))
|
i2c.Bus.TXD.Set(uint32(data))
|
||||||
for i2c.Bus.EVENTS_TXDSENT.Get() == 0 {
|
for i2c.Bus.EVENTS_TXDSENT.Get() == 0 {
|
||||||
if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 {
|
if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 {
|
||||||
i2c.Bus.EVENTS_ERROR.Set(0)
|
i2c.Bus.EVENTS_ERROR.Set(0)
|
||||||
return errI2CBusError
|
return errI2CBusError
|
||||||
}
|
}
|
||||||
|
tries++
|
||||||
|
if tries >= i2cTimeout {
|
||||||
|
return errI2CWriteTimeout
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i2c.Bus.EVENTS_TXDSENT.Set(0)
|
i2c.Bus.EVENTS_TXDSENT.Set(0)
|
||||||
return nil
|
return nil
|
||||||
@@ -95,11 +110,16 @@ func (i2c *I2C) writeByte(data byte) error {
|
|||||||
|
|
||||||
// readByte reads a single byte from the I2C bus when it is ready.
|
// readByte reads a single byte from the I2C bus when it is ready.
|
||||||
func (i2c *I2C) readByte() (byte, error) {
|
func (i2c *I2C) readByte() (byte, error) {
|
||||||
|
tries := 0
|
||||||
for i2c.Bus.EVENTS_RXDREADY.Get() == 0 {
|
for i2c.Bus.EVENTS_RXDREADY.Get() == 0 {
|
||||||
if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 {
|
if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 {
|
||||||
i2c.Bus.EVENTS_ERROR.Set(0)
|
i2c.Bus.EVENTS_ERROR.Set(0)
|
||||||
return 0, errI2CBusError
|
return 0, errI2CBusError
|
||||||
}
|
}
|
||||||
|
tries++
|
||||||
|
if tries >= i2cTimeout {
|
||||||
|
return 0, errI2CReadTimeout
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i2c.Bus.EVENTS_RXDREADY.Set(0)
|
i2c.Bus.EVENTS_RXDREADY.Set(0)
|
||||||
return byte(i2c.Bus.RXD.Get()), nil
|
return byte(i2c.Bus.RXD.Get()), nil
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ func (u *UART) handleStatusInterrupt(interrupt.Interrupt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (u *UART) WriteByte(c byte) error {
|
func (u *UART) writeByte(c byte) error {
|
||||||
if !u.Configured {
|
if !u.Configured {
|
||||||
return ErrNotConfigured
|
return ErrNotConfigured
|
||||||
}
|
}
|
||||||
@@ -305,3 +305,5 @@ func (u *UART) WriteByte(c byte) error {
|
|||||||
u.C2.Set(uartC2TXActive)
|
u.C2.Set(uartC2TXActive)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ func (clk *clock) configure(src, auxsrc, srcFreq, freq uint32) {
|
|||||||
// Must be called before any other clock function.
|
// Must be called before any other clock function.
|
||||||
func (clks *clocksType) init() {
|
func (clks *clocksType) init() {
|
||||||
// Start the watchdog tick
|
// Start the watchdog tick
|
||||||
watchdog.startTick(xoscFreq)
|
Watchdog.startTick(xoscFreq)
|
||||||
|
|
||||||
// Disable resus that may be enabled from previous software
|
// Disable resus that may be enabled from previous software
|
||||||
clks.resus.ctrl.Set(0)
|
clks.resus.ctrl.Set(0)
|
||||||
|
|||||||
@@ -0,0 +1,97 @@
|
|||||||
|
//go:build rp2040
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EnterBootloader should perform a system reset in preparation
|
||||||
|
// to switch to the bootloader to flash new firmware.
|
||||||
|
func EnterBootloader() {
|
||||||
|
enterBootloader()
|
||||||
|
}
|
||||||
|
|
||||||
|
// compile-time check for ensuring we fulfill BlockDevice interface
|
||||||
|
var _ BlockDevice = flashBlockDevice{}
|
||||||
|
|
||||||
|
var Flash flashBlockDevice
|
||||||
|
|
||||||
|
type flashBlockDevice struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadAt reads the given number of bytes from the block device.
|
||||||
|
func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) {
|
||||||
|
if readAddress(off) > FlashDataEnd() {
|
||||||
|
return 0, errFlashCannotReadPastEOF
|
||||||
|
}
|
||||||
|
|
||||||
|
data := unsafe.Slice((*byte)(unsafe.Pointer(readAddress(off))), len(p))
|
||||||
|
copy(p, data)
|
||||||
|
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteAt writes the given number of bytes to the block device.
|
||||||
|
// Only word (32 bits) length data can be programmed.
|
||||||
|
// If the length of p is not long enough it will be padded with 0xFF bytes.
|
||||||
|
// This method assumes that the destination is already erased.
|
||||||
|
func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
|
||||||
|
return f.writeAt(p, off)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the number of bytes in this block device.
|
||||||
|
func (f flashBlockDevice) Size() int64 {
|
||||||
|
return int64(FlashDataEnd() - FlashDataStart())
|
||||||
|
}
|
||||||
|
|
||||||
|
const writeBlockSize = 1 << 8
|
||||||
|
|
||||||
|
// WriteBlockSize returns the block size in which data can be written to
|
||||||
|
// memory. It can be used by a client to optimize writes, non-aligned writes
|
||||||
|
// should always work correctly.
|
||||||
|
func (f flashBlockDevice) WriteBlockSize() int64 {
|
||||||
|
return writeBlockSize
|
||||||
|
}
|
||||||
|
|
||||||
|
const eraseBlockSizeValue = 1 << 12
|
||||||
|
|
||||||
|
func eraseBlockSize() int64 {
|
||||||
|
return eraseBlockSizeValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// EraseBlockSize returns the smallest erasable area on this particular chip
|
||||||
|
// in bytes. This is used for the block size in EraseBlocks.
|
||||||
|
func (f flashBlockDevice) EraseBlockSize() int64 {
|
||||||
|
return eraseBlockSize()
|
||||||
|
}
|
||||||
|
|
||||||
|
// EraseBlocks erases the given number of blocks. An implementation may
|
||||||
|
// transparently coalesce ranges of blocks into larger bundles if the chip
|
||||||
|
// supports this. The start and len parameters are in block numbers, use
|
||||||
|
// EraseBlockSize to map addresses to blocks.
|
||||||
|
func (f flashBlockDevice) EraseBlocks(start, length int64) error {
|
||||||
|
return f.eraseBlocks(start, length)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pad data if needed so it is long enough for correct byte alignment on writes.
|
||||||
|
func (f flashBlockDevice) pad(p []byte) []byte {
|
||||||
|
overflow := int64(len(p)) % f.WriteBlockSize()
|
||||||
|
if overflow == 0 {
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow))
|
||||||
|
return append(p, padding...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the correct address to be used for write
|
||||||
|
func writeAddress(off int64) uintptr {
|
||||||
|
return readAddress(off) - uintptr(memoryStart)
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the correct address to be used for reads
|
||||||
|
func readAddress(off int64) uintptr {
|
||||||
|
return FlashDataStart() + uintptr(off)
|
||||||
|
}
|
||||||
@@ -174,6 +174,9 @@ func (p Pin) init() {
|
|||||||
|
|
||||||
// Configure configures the gpio pin as per mode.
|
// Configure configures the gpio pin as per mode.
|
||||||
func (p Pin) Configure(config PinConfig) {
|
func (p Pin) Configure(config PinConfig) {
|
||||||
|
if p == NoPin {
|
||||||
|
return
|
||||||
|
}
|
||||||
p.init()
|
p.init()
|
||||||
mask := uint32(1) << p
|
mask := uint32(1) << p
|
||||||
switch config.Mode {
|
switch config.Mode {
|
||||||
@@ -213,6 +216,9 @@ func (p Pin) Configure(config PinConfig) {
|
|||||||
|
|
||||||
// Set drives the pin high if value is true else drives it low.
|
// Set drives the pin high if value is true else drives it low.
|
||||||
func (p Pin) Set(value bool) {
|
func (p Pin) Set(value bool) {
|
||||||
|
if p == NoPin {
|
||||||
|
return
|
||||||
|
}
|
||||||
if value {
|
if value {
|
||||||
p.set()
|
p.set()
|
||||||
} else {
|
} else {
|
||||||
@@ -251,6 +257,9 @@ var (
|
|||||||
// nil func to unset the pin change interrupt. If you do so, the change
|
// nil func to unset the pin change interrupt. If you do so, the change
|
||||||
// parameter is ignored and can be set to any value (such as 0).
|
// parameter is ignored and can be set to any value (such as 0).
|
||||||
func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
|
func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
|
||||||
|
if p == NoPin {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
if p > 31 || p < 0 {
|
if p > 31 || p < 0 {
|
||||||
return ErrInvalidInputPin
|
return ErrInvalidInputPin
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"runtime/interrupt"
|
"runtime/interrupt"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@@ -136,40 +135,14 @@ void ram_func flash_erase_blocks(uint32_t offset, size_t count)
|
|||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
// EnterBootloader should perform a system reset in preparation
|
func enterBootloader() {
|
||||||
// to switch to the bootloader to flash new firmware.
|
|
||||||
func EnterBootloader() {
|
|
||||||
C.reset_usb_boot(0, 0)
|
C.reset_usb_boot(0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flash related code
|
// Flash related code
|
||||||
const memoryStart = C.XIP_BASE // memory start for purpose of erase
|
const memoryStart = C.XIP_BASE // memory start for purpose of erase
|
||||||
|
|
||||||
// compile-time check for ensuring we fulfill BlockDevice interface
|
func (f flashBlockDevice) writeAt(p []byte, off int64) (n int, err error) {
|
||||||
var _ BlockDevice = flashBlockDevice{}
|
|
||||||
|
|
||||||
var Flash flashBlockDevice
|
|
||||||
|
|
||||||
type flashBlockDevice struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReadAt reads the given number of bytes from the block device.
|
|
||||||
func (f flashBlockDevice) ReadAt(p []byte, off int64) (n int, err error) {
|
|
||||||
if readAddress(off) > FlashDataEnd() {
|
|
||||||
return 0, errFlashCannotReadPastEOF
|
|
||||||
}
|
|
||||||
|
|
||||||
data := unsafe.Slice((*byte)(unsafe.Pointer(readAddress(off))), len(p))
|
|
||||||
copy(p, data)
|
|
||||||
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteAt writes the given number of bytes to the block device.
|
|
||||||
// Only word (32 bits) length data can be programmed.
|
|
||||||
// If the length of p is not long enough it will be padded with 0xFF bytes.
|
|
||||||
// This method assumes that the destination is already erased.
|
|
||||||
func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
|
|
||||||
if writeAddress(off)+uintptr(C.XIP_BASE) > FlashDataEnd() {
|
if writeAddress(off)+uintptr(C.XIP_BASE) > FlashDataEnd() {
|
||||||
return 0, errFlashCannotWritePastEOF
|
return 0, errFlashCannotWritePastEOF
|
||||||
}
|
}
|
||||||
@@ -190,37 +163,7 @@ func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
|
|||||||
return len(padded), nil
|
return len(padded), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the number of bytes in this block device.
|
func (f flashBlockDevice) eraseBlocks(start, length int64) error {
|
||||||
func (f flashBlockDevice) Size() int64 {
|
|
||||||
return int64(FlashDataEnd() - FlashDataStart())
|
|
||||||
}
|
|
||||||
|
|
||||||
const writeBlockSize = 1 << 8
|
|
||||||
|
|
||||||
// WriteBlockSize returns the block size in which data can be written to
|
|
||||||
// memory. It can be used by a client to optimize writes, non-aligned writes
|
|
||||||
// should always work correctly.
|
|
||||||
func (f flashBlockDevice) WriteBlockSize() int64 {
|
|
||||||
return writeBlockSize
|
|
||||||
}
|
|
||||||
|
|
||||||
const eraseBlockSizeValue = 1 << 12
|
|
||||||
|
|
||||||
func eraseBlockSize() int64 {
|
|
||||||
return eraseBlockSizeValue
|
|
||||||
}
|
|
||||||
|
|
||||||
// EraseBlockSize returns the smallest erasable area on this particular chip
|
|
||||||
// in bytes. This is used for the block size in EraseBlocks.
|
|
||||||
func (f flashBlockDevice) EraseBlockSize() int64 {
|
|
||||||
return eraseBlockSize()
|
|
||||||
}
|
|
||||||
|
|
||||||
// EraseBlocks erases the given number of blocks. An implementation may
|
|
||||||
// transparently coalesce ranges of blocks into larger bundles if the chip
|
|
||||||
// supports this. The start and len parameters are in block numbers, use
|
|
||||||
// EraseBlockSize to map addresses to blocks.
|
|
||||||
func (f flashBlockDevice) EraseBlocks(start, length int64) error {
|
|
||||||
address := writeAddress(start * f.EraseBlockSize())
|
address := writeAddress(start * f.EraseBlockSize())
|
||||||
if address+uintptr(C.XIP_BASE) > FlashDataEnd() {
|
if address+uintptr(C.XIP_BASE) > FlashDataEnd() {
|
||||||
return errFlashCannotErasePastEOF
|
return errFlashCannotErasePastEOF
|
||||||
@@ -233,24 +176,3 @@ func (f flashBlockDevice) EraseBlocks(start, length int64) error {
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// pad data if needed so it is long enough for correct byte alignment on writes.
|
|
||||||
func (f flashBlockDevice) pad(p []byte) []byte {
|
|
||||||
overflow := int64(len(p)) % f.WriteBlockSize()
|
|
||||||
if overflow == 0 {
|
|
||||||
return p
|
|
||||||
}
|
|
||||||
|
|
||||||
padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow))
|
|
||||||
return append(p, padding...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the correct address to be used for write
|
|
||||||
func writeAddress(off int64) uintptr {
|
|
||||||
return readAddress(off) - uintptr(C.XIP_BASE)
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the correct address to be used for reads
|
|
||||||
func readAddress(off int64) uintptr {
|
|
||||||
return FlashDataStart() + uintptr(off)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -368,6 +368,9 @@ func (spi SPI) rx(rx []byte, txrepeat byte) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for spi.isBusy() {
|
||||||
|
gosched()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,6 +400,8 @@ func (spi SPI) txrx(tx, rx []byte) error {
|
|||||||
// Transaction ended early due to timeout
|
// Transaction ended early due to timeout
|
||||||
return ErrSPITimeout
|
return ErrSPITimeout
|
||||||
}
|
}
|
||||||
|
for spi.isBusy() {
|
||||||
|
gosched()
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -86,9 +86,10 @@ func (uart *UART) SetBaudRate(br uint32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (uart *UART) WriteByte(c byte) error {
|
func (uart *UART) writeByte(c byte) error {
|
||||||
// wait until buffer is not full
|
// wait until buffer is not full
|
||||||
for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_TXFF) {
|
for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_TXFF) {
|
||||||
|
gosched()
|
||||||
}
|
}
|
||||||
|
|
||||||
// write data
|
// write data
|
||||||
@@ -96,6 +97,12 @@ func (uart *UART) WriteByte(c byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {
|
||||||
|
for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_BUSY) {
|
||||||
|
gosched()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SetFormat for number of data bits, stop bits, and parity for the UART.
|
// SetFormat for number of data bits, stop bits, and parity for the UART.
|
||||||
func (uart *UART) SetFormat(databits, stopbits uint8, parity UARTParity) error {
|
func (uart *UART) SetFormat(databits, stopbits uint8, parity UARTParity) error {
|
||||||
var pen, pev uint8
|
var pen, pev uint8
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"device/arm"
|
||||||
"device/rp"
|
"device/rp"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -87,6 +88,7 @@ func hw_enumeration_fix_force_ls_j() {
|
|||||||
rp.USBCTRL_REGS.USB_MUXING.Set(rp.USBCTRL_REGS_USB_MUXING_TO_DIGITAL_PAD | rp.USBCTRL_REGS_USB_MUXING_SOFTCON)
|
rp.USBCTRL_REGS.USB_MUXING.Set(rp.USBCTRL_REGS_USB_MUXING_TO_DIGITAL_PAD | rp.USBCTRL_REGS_USB_MUXING_SOFTCON)
|
||||||
|
|
||||||
// LS_J is now forced but while loop here just to check
|
// LS_J is now forced but while loop here just to check
|
||||||
|
waitCycles(125000)
|
||||||
|
|
||||||
// if timer pool disabled, or no timer available, have to busy wait.
|
// if timer pool disabled, or no timer available, have to busy wait.
|
||||||
hw_enumeration_fix_finish()
|
hw_enumeration_fix_finish()
|
||||||
@@ -109,3 +111,10 @@ func hw_enumeration_fix_finish() {
|
|||||||
// Restore the pad ctrl value
|
// Restore the pad ctrl value
|
||||||
padsBank0.io[dp].Set(padCtrlPrev)
|
padsBank0.io[dp].Set(padCtrlPrev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func waitCycles(n int) {
|
||||||
|
for n > 0 {
|
||||||
|
arm.Asm("nop")
|
||||||
|
n--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,24 +4,67 @@ package machine
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"device/rp"
|
"device/rp"
|
||||||
"runtime/volatile"
|
|
||||||
"unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type watchdogType struct {
|
// Watchdog provides access to the hardware watchdog available
|
||||||
ctrl volatile.Register32
|
// in the RP2040.
|
||||||
load volatile.Register32
|
var Watchdog = &watchdogImpl{}
|
||||||
reason volatile.Register32
|
|
||||||
scratch [8]volatile.Register32
|
const (
|
||||||
tick volatile.Register32
|
// WatchdogMaxTimeout in milliseconds (approx 8.3s).
|
||||||
|
//
|
||||||
|
// Nominal 1us per watchdog tick, 24-bit counter,
|
||||||
|
// but due to errata two ticks consumed per 1us.
|
||||||
|
// See: Errata RP2040-E1
|
||||||
|
WatchdogMaxTimeout = (rp.WATCHDOG_LOAD_LOAD_Msk / 1000) / 2
|
||||||
|
)
|
||||||
|
|
||||||
|
type watchdogImpl struct {
|
||||||
|
// The value to reset the counter to on each Update
|
||||||
|
loadValue uint32
|
||||||
}
|
}
|
||||||
|
|
||||||
var watchdog = (*watchdogType)(unsafe.Pointer(rp.WATCHDOG))
|
// Configure the watchdog.
|
||||||
|
//
|
||||||
|
// This method should not be called after the watchdog is started and on
|
||||||
|
// some platforms attempting to reconfigure after starting the watchdog
|
||||||
|
// is explicitly forbidden / will not work.
|
||||||
|
func (wd *watchdogImpl) Configure(config WatchdogConfig) error {
|
||||||
|
// x2 due to errata RP2040-E1
|
||||||
|
wd.loadValue = config.TimeoutMillis * 1000 * 2
|
||||||
|
if wd.loadValue > rp.WATCHDOG_LOAD_LOAD_Msk {
|
||||||
|
wd.loadValue = rp.WATCHDOG_LOAD_LOAD_Msk
|
||||||
|
}
|
||||||
|
|
||||||
|
rp.WATCHDOG.CTRL.ClearBits(rp.WATCHDOG_CTRL_ENABLE)
|
||||||
|
|
||||||
|
// Reset everything apart from ROSC and XOSC
|
||||||
|
rp.PSM.WDSEL.Set(0x0001ffff &^ (rp.PSM_WDSEL_ROSC | rp.PSM_WDSEL_XOSC))
|
||||||
|
|
||||||
|
// Pause watchdog during debug
|
||||||
|
rp.WATCHDOG.CTRL.SetBits(rp.WATCHDOG_CTRL_PAUSE_DBG0 | rp.WATCHDOG_CTRL_PAUSE_DBG1 | rp.WATCHDOG_CTRL_PAUSE_JTAG)
|
||||||
|
|
||||||
|
// Load initial counter
|
||||||
|
rp.WATCHDOG.LOAD.Set(wd.loadValue)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts the watchdog.
|
||||||
|
func (wd *watchdogImpl) Start() error {
|
||||||
|
rp.WATCHDOG.CTRL.SetBits(rp.WATCHDOG_CTRL_ENABLE)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the watchdog, indicating that the app is healthy.
|
||||||
|
func (wd *watchdogImpl) Update() {
|
||||||
|
rp.WATCHDOG.LOAD.Set(wd.loadValue)
|
||||||
|
}
|
||||||
|
|
||||||
// startTick starts the watchdog tick.
|
// startTick starts the watchdog tick.
|
||||||
// cycles needs to be a divider that when applied to the xosc input,
|
// cycles needs to be a divider that when applied to the xosc input,
|
||||||
// produces a 1MHz clock. So if the xosc frequency is 12MHz,
|
// produces a 1MHz clock. So if the xosc frequency is 12MHz,
|
||||||
// this will need to be 12.
|
// this will need to be 12.
|
||||||
func (wd *watchdogType) startTick(cycles uint32) {
|
func (wd *watchdogImpl) startTick(cycles uint32) {
|
||||||
wd.tick.Set(cycles | rp.WATCHDOG_TICK_ENABLE)
|
rp.WATCHDOG.TICK.Set(cycles | rp.WATCHDOG_TICK_ENABLE)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
//go:build stm32
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import "device/stm32"
|
||||||
|
|
||||||
|
var (
|
||||||
|
Watchdog = &watchdogImpl{}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// WatchdogMaxTimeout in milliseconds (32.768s)
|
||||||
|
//
|
||||||
|
// Timeout is based on 12-bit counter with /256 divider on
|
||||||
|
// 32.768kHz clock. See 21.3.3 of RM0090 for table.
|
||||||
|
WatchdogMaxTimeout = ((0xfff + 1) * 256 * 1024) / 32768
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Enable access to PR, RLR and WINR registers (0x5555)
|
||||||
|
iwdgKeyEnable = 0x5555
|
||||||
|
// Reset the watchdog value (0xAAAA)
|
||||||
|
iwdgKeyReset = 0xaaaa
|
||||||
|
// Start the watchdog (0xCCCC)
|
||||||
|
iwdgKeyStart = 0xcccc
|
||||||
|
// Divide by 256
|
||||||
|
iwdgDiv256 = 6
|
||||||
|
)
|
||||||
|
|
||||||
|
type watchdogImpl struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the watchdog.
|
||||||
|
//
|
||||||
|
// This method should not be called after the watchdog is started and on
|
||||||
|
// some platforms attempting to reconfigure after starting the watchdog
|
||||||
|
// is explicitly forbidden / will not work.
|
||||||
|
func (wd *watchdogImpl) Configure(config WatchdogConfig) error {
|
||||||
|
|
||||||
|
// Enable configuration of IWDG
|
||||||
|
stm32.IWDG.KR.Set(iwdgKeyEnable)
|
||||||
|
|
||||||
|
// Unconditionally divide by /256 since we don't really need accuracy
|
||||||
|
// less than 8ms
|
||||||
|
stm32.IWDG.PR.Set(iwdgDiv256)
|
||||||
|
|
||||||
|
timeout := config.TimeoutMillis
|
||||||
|
if timeout > WatchdogMaxTimeout {
|
||||||
|
timeout = WatchdogMaxTimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set reload value based on /256 divider
|
||||||
|
stm32.IWDG.RLR.Set(((config.TimeoutMillis*32768 + (256 * 1024) - 1) / (256 * 1024)) - 1)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts the watchdog.
|
||||||
|
func (wd *watchdogImpl) Start() error {
|
||||||
|
stm32.IWDG.KR.Set(iwdgKeyStart)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the watchdog, indicating that `source` is healthy.
|
||||||
|
func (wd *watchdogImpl) Update() {
|
||||||
|
stm32.IWDG.KR.Set(iwdgKeyReset)
|
||||||
|
}
|
||||||
@@ -74,10 +74,12 @@ func (uart *UART) SetBaudRate(br uint32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte writes a byte of data to the UART.
|
// WriteByte writes a byte of data to the UART.
|
||||||
func (uart *UART) WriteByte(c byte) error {
|
func (uart *UART) writeByte(c byte) error {
|
||||||
uart.txReg.Set(uint32(c))
|
uart.txReg.Set(uint32(c))
|
||||||
|
|
||||||
for !uart.statusReg.HasBits(uart.txEmptyFlag) {
|
for !uart.statusReg.HasBits(uart.txEmptyFlag) {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (uart *UART) flush() {}
|
||||||
|
|||||||
+20
-4
@@ -59,11 +59,27 @@ func (uart *UART) Read(data []byte) (n int, err error) {
|
|||||||
return size, nil
|
return size, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write data to the UART.
|
// WriteByte writes a byte of data over the UART's Tx.
|
||||||
func (uart *UART) Write(data []byte) (n int, err error) {
|
// This function blocks until the data is finished being sent.
|
||||||
for _, v := range data {
|
func (uart *UART) WriteByte(c byte) error {
|
||||||
uart.WriteByte(v)
|
err := uart.writeByte(c)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
uart.flush() // flush() blocks until all data has been transmitted.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write data over the UART's Tx.
|
||||||
|
// This function blocks until the data is finished being sent.
|
||||||
|
func (uart *UART) Write(data []byte) (n int, err error) {
|
||||||
|
for i, v := range data {
|
||||||
|
err = uart.writeByte(v)
|
||||||
|
if err != nil {
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uart.flush() // flush() blocks until all data has been transmitted.
|
||||||
return len(data), nil
|
return len(data), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+48
-54
@@ -29,9 +29,7 @@ type Serialer interface {
|
|||||||
RTS() bool
|
RTS() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var usbDescriptor = descriptor.CDC
|
var usbDescriptor descriptor.Descriptor
|
||||||
|
|
||||||
var usbDescriptorConfig uint8 = usb.DescriptorConfigCDC
|
|
||||||
|
|
||||||
func usbVendorID() uint16 {
|
func usbVendorID() uint16 {
|
||||||
if usb.VendorID != 0 {
|
if usb.VendorID != 0 {
|
||||||
@@ -138,18 +136,6 @@ func sendDescriptor(setup usb.Setup) {
|
|||||||
sendUSBPacket(0, usbDescriptor.Configuration, setup.WLength)
|
sendUSBPacket(0, usbDescriptor.Configuration, setup.WLength)
|
||||||
return
|
return
|
||||||
case descriptor.TypeDevice:
|
case descriptor.TypeDevice:
|
||||||
// composite descriptor
|
|
||||||
switch {
|
|
||||||
case (usbDescriptorConfig & usb.DescriptorConfigHID) > 0:
|
|
||||||
usbDescriptor = descriptor.CDCHID
|
|
||||||
case (usbDescriptorConfig & usb.DescriptorConfigMIDI) > 0:
|
|
||||||
usbDescriptor = descriptor.CDCMIDI
|
|
||||||
case (usbDescriptorConfig & usb.DescriptorConfigJoystick) > 0:
|
|
||||||
usbDescriptor = descriptor.CDCJoystick
|
|
||||||
default:
|
|
||||||
usbDescriptor = descriptor.CDC
|
|
||||||
}
|
|
||||||
|
|
||||||
usbDescriptor.Configure(usbVendorID(), usbProductID())
|
usbDescriptor.Configure(usbVendorID(), usbProductID())
|
||||||
sendUSBPacket(0, usbDescriptor.Device, setup.WLength)
|
sendUSBPacket(0, usbDescriptor.Device, setup.WLength)
|
||||||
return
|
return
|
||||||
@@ -273,48 +259,56 @@ func handleStandardSetup(setup usb.Setup) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func EnableCDC(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) {
|
func EnableCDC(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) {
|
||||||
usbDescriptorConfig |= usb.DescriptorConfigCDC
|
if len(usbDescriptor.Device) == 0 {
|
||||||
endPoints[usb.CDC_ENDPOINT_ACM] = (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn)
|
usbDescriptor = descriptor.CDC
|
||||||
endPoints[usb.CDC_ENDPOINT_OUT] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut)
|
}
|
||||||
endPoints[usb.CDC_ENDPOINT_IN] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn)
|
// Initialization of endpoints is required even for non-CDC
|
||||||
usbRxHandler[usb.CDC_ENDPOINT_OUT] = rxHandler
|
ConfigureUSBEndpoint(usbDescriptor,
|
||||||
usbTxHandler[usb.CDC_ENDPOINT_IN] = txHandler
|
[]usb.EndpointConfig{
|
||||||
usbSetupHandler[usb.CDC_ACM_INTERFACE] = setupHandler // 0x02 (Communications and CDC Control)
|
{
|
||||||
usbSetupHandler[usb.CDC_DATA_INTERFACE] = nil // 0x0A (CDC-Data)
|
Index: usb.CDC_ENDPOINT_ACM,
|
||||||
|
IsIn: true,
|
||||||
|
Type: usb.ENDPOINT_TYPE_INTERRUPT,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Index: usb.CDC_ENDPOINT_OUT,
|
||||||
|
IsIn: false,
|
||||||
|
Type: usb.ENDPOINT_TYPE_BULK,
|
||||||
|
RxHandler: rxHandler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Index: usb.CDC_ENDPOINT_IN,
|
||||||
|
IsIn: true,
|
||||||
|
Type: usb.ENDPOINT_TYPE_BULK,
|
||||||
|
TxHandler: txHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]usb.SetupConfig{
|
||||||
|
{
|
||||||
|
Index: usb.CDC_ACM_INTERFACE,
|
||||||
|
Handler: setupHandler,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableHID enables HID. This function must be executed from the init().
|
func ConfigureUSBEndpoint(desc descriptor.Descriptor, epSettings []usb.EndpointConfig, setup []usb.SetupConfig) {
|
||||||
func EnableHID(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) {
|
usbDescriptor = desc
|
||||||
usbDescriptorConfig |= usb.DescriptorConfigHID
|
|
||||||
endPoints[usb.HID_ENDPOINT_IN] = (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn)
|
|
||||||
usbTxHandler[usb.HID_ENDPOINT_IN] = txHandler
|
|
||||||
usbSetupHandler[usb.HID_INTERFACE] = setupHandler // 0x03 (HID - Human Interface Device)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EnableMIDI enables MIDI. This function must be executed from the init().
|
for _, ep := range epSettings {
|
||||||
func EnableMIDI(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool) {
|
if ep.IsIn {
|
||||||
usbDescriptorConfig |= usb.DescriptorConfigMIDI
|
endPoints[ep.Index] = uint32(ep.Type | usb.EndpointIn)
|
||||||
endPoints[usb.MIDI_ENDPOINT_OUT] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointOut)
|
if ep.TxHandler != nil {
|
||||||
endPoints[usb.MIDI_ENDPOINT_IN] = (usb.ENDPOINT_TYPE_BULK | usb.EndpointIn)
|
usbTxHandler[ep.Index] = ep.TxHandler
|
||||||
usbRxHandler[usb.MIDI_ENDPOINT_OUT] = rxHandler
|
}
|
||||||
usbTxHandler[usb.MIDI_ENDPOINT_IN] = txHandler
|
} else {
|
||||||
}
|
endPoints[ep.Index] = uint32(ep.Type | usb.EndpointOut)
|
||||||
|
if ep.RxHandler != nil {
|
||||||
// EnableJoystick enables HID. This function must be executed from the init().
|
usbRxHandler[ep.Index] = ep.RxHandler
|
||||||
func EnableJoystick(txHandler func(), rxHandler func([]byte), setupHandler func(usb.Setup) bool, hidDesc []byte) {
|
}
|
||||||
class, err := descriptor.FindClassHIDType(descriptor.CDCJoystick.Configuration, descriptor.ClassHIDJoystick.Bytes())
|
}
|
||||||
if err != nil {
|
|
||||||
// TODO: some way to notify about error
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class.ClassLength(uint16(len(hidDesc)))
|
for _, s := range setup {
|
||||||
descriptor.CDCJoystick.HID[2] = hidDesc
|
usbSetupHandler[s.Index] = s.Handler
|
||||||
|
}
|
||||||
usbDescriptorConfig |= usb.DescriptorConfigJoystick
|
|
||||||
endPoints[usb.HID_ENDPOINT_OUT] = (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointOut)
|
|
||||||
usbRxHandler[usb.HID_ENDPOINT_OUT] = rxHandler
|
|
||||||
endPoints[usb.HID_ENDPOINT_IN] = (usb.ENDPOINT_TYPE_INTERRUPT | usb.EndpointIn)
|
|
||||||
usbTxHandler[usb.HID_ENDPOINT_IN] = txHandler
|
|
||||||
usbSetupHandler[usb.HID_INTERFACE] = setupHandler // 0x03 (HID - Human Interface Device)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package midi
|
|||||||
import (
|
import (
|
||||||
"machine"
|
"machine"
|
||||||
"machine/usb"
|
"machine/usb"
|
||||||
|
"machine/usb/descriptor"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -40,7 +41,23 @@ func newMidi() *midi {
|
|||||||
m := &midi{
|
m := &midi{
|
||||||
buf: NewRingBuffer(),
|
buf: NewRingBuffer(),
|
||||||
}
|
}
|
||||||
machine.EnableMIDI(m.Handler, m.RxHandler, nil)
|
machine.ConfigureUSBEndpoint(descriptor.CDCMIDI,
|
||||||
|
[]usb.EndpointConfig{
|
||||||
|
{
|
||||||
|
Index: usb.MIDI_ENDPOINT_OUT,
|
||||||
|
IsIn: false,
|
||||||
|
Type: usb.ENDPOINT_TYPE_BULK,
|
||||||
|
RxHandler: m.RxHandler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Index: usb.MIDI_ENDPOINT_IN,
|
||||||
|
IsIn: true,
|
||||||
|
Type: usb.ENDPOINT_TYPE_BULK,
|
||||||
|
TxHandler: m.Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]usb.SetupConfig{},
|
||||||
|
)
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package usb
|
||||||
|
|
||||||
|
type EndpointConfig struct {
|
||||||
|
Index uint8
|
||||||
|
IsIn bool
|
||||||
|
TxHandler func()
|
||||||
|
RxHandler func([]byte)
|
||||||
|
Type uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type SetupConfig struct {
|
||||||
|
Index uint8
|
||||||
|
Handler func(Setup) bool
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ var interfaceHID = [interfaceTypeLen]byte{
|
|||||||
TypeInterface,
|
TypeInterface,
|
||||||
0x02, // InterfaceNumber
|
0x02, // InterfaceNumber
|
||||||
0x00, // AlternateSetting
|
0x00, // AlternateSetting
|
||||||
0x01, // NumEndpoints
|
0x02, // NumEndpoints
|
||||||
0x03, // InterfaceClass
|
0x03, // InterfaceClass
|
||||||
0x00, // InterfaceSubClass
|
0x00, // InterfaceSubClass
|
||||||
0x00, // InterfaceProtocol
|
0x00, // InterfaceProtocol
|
||||||
@@ -103,7 +103,7 @@ var classHID = [ClassHIDTypeLen]byte{
|
|||||||
0x00, // CountryCode
|
0x00, // CountryCode
|
||||||
0x01, // NumDescriptors
|
0x01, // NumDescriptors
|
||||||
0x22, // ClassType
|
0x22, // ClassType
|
||||||
0x7E, // ClassLength L
|
0x90, // ClassLength L
|
||||||
0x00, // ClassLength H
|
0x00, // ClassLength H
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +128,7 @@ var CDCHID = Descriptor{
|
|||||||
InterfaceHID.Bytes(),
|
InterfaceHID.Bytes(),
|
||||||
ClassHID.Bytes(),
|
ClassHID.Bytes(),
|
||||||
EndpointEP4IN.Bytes(),
|
EndpointEP4IN.Bytes(),
|
||||||
|
EndpointEP5OUT.Bytes(),
|
||||||
}),
|
}),
|
||||||
HID: map[uint16][]byte{
|
HID: map[uint16][]byte{
|
||||||
2: Append([][]byte{
|
2: Append([][]byte{
|
||||||
@@ -147,6 +148,15 @@ var CDCHID = Descriptor{
|
|||||||
HIDReportCount(1),
|
HIDReportCount(1),
|
||||||
HIDReportSize(8),
|
HIDReportSize(8),
|
||||||
HIDInputConstVarAbs,
|
HIDInputConstVarAbs,
|
||||||
|
HIDReportCount(3),
|
||||||
|
HIDReportSize(1),
|
||||||
|
HIDUsagePageLED,
|
||||||
|
HIDUsageMinimum(1),
|
||||||
|
HIDUsageMaximum(3),
|
||||||
|
HIDOutputDataVarAbs,
|
||||||
|
HIDReportCount(5),
|
||||||
|
HIDReportSize(1),
|
||||||
|
HIDOutputConstVarAbs,
|
||||||
HIDReportCount(6),
|
HIDReportCount(6),
|
||||||
HIDReportSize(8),
|
HIDReportSize(8),
|
||||||
HIDLogicalMinimum(0),
|
HIDLogicalMinimum(0),
|
||||||
|
|||||||
@@ -3,21 +3,29 @@ package descriptor
|
|||||||
const (
|
const (
|
||||||
hidUsagePage = 0x05
|
hidUsagePage = 0x05
|
||||||
hidUsage = 0x09
|
hidUsage = 0x09
|
||||||
hidLogicalMinimum = 0x15
|
hidLogicalMinimum = 0x14
|
||||||
hidLogicalMaximum = 0x25
|
hidLogicalMaximum = 0x24
|
||||||
hidUsageMinimum = 0x19
|
hidUsageMinimum = 0x18
|
||||||
hidUsageMaximum = 0x29
|
hidUsageMaximum = 0x28
|
||||||
hidPhysicalMinimum = 0x35
|
hidPhysicalMinimum = 0x34
|
||||||
hidPhysicalMaximum = 0x46
|
hidPhysicalMaximum = 0x44
|
||||||
hidUnitExponent = 0x55
|
hidUnitExponent = 0x55
|
||||||
hidUnit = 0x65
|
hidUnit = 0x65
|
||||||
hidCollection = 0xa1
|
hidCollection = 0xa1
|
||||||
hidInput = 0x81
|
hidInput = 0x81
|
||||||
|
hidOutput = 0x91
|
||||||
hidReportSize = 0x75
|
hidReportSize = 0x75
|
||||||
hidReportCount = 0x95
|
hidReportCount = 0x95
|
||||||
hidReportID = 0x85
|
hidReportID = 0x85
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
hidSizeValue0 = 0x00
|
||||||
|
hidSizeValue1 = 0x01
|
||||||
|
hidSizeValue2 = 0x02
|
||||||
|
hidSizeValue4 = 0x03
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
HIDUsagePageGenericDesktop = []byte{hidUsagePage, 0x01}
|
HIDUsagePageGenericDesktop = []byte{hidUsagePage, 0x01}
|
||||||
HIDUsagePageSimulationControls = []byte{hidUsagePage, 0x02}
|
HIDUsagePageSimulationControls = []byte{hidUsagePage, 0x02}
|
||||||
@@ -114,6 +122,12 @@ var (
|
|||||||
|
|
||||||
// Input (Data, Variable, Relative), 2 position bytes (X & Y)
|
// Input (Data, Variable, Relative), 2 position bytes (X & Y)
|
||||||
HIDInputDataVarRel = []byte{hidInput, 0x06}
|
HIDInputDataVarRel = []byte{hidInput, 0x06}
|
||||||
|
|
||||||
|
// Output (Data, Variable, Absolute), Modifier byte
|
||||||
|
HIDOutputDataVarAbs = []byte{hidOutput, 0x02}
|
||||||
|
|
||||||
|
// Output (Const, Variable, Absolute), Modifier byte
|
||||||
|
HIDOutputConstVarAbs = []byte{hidOutput, 0x03}
|
||||||
)
|
)
|
||||||
|
|
||||||
func HIDReportSize(size int) []byte {
|
func HIDReportSize(size int) []byte {
|
||||||
@@ -129,51 +143,69 @@ func HIDReportID(id int) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func HIDLogicalMinimum(min int) []byte {
|
func HIDLogicalMinimum(min int) []byte {
|
||||||
if min > 255 {
|
switch {
|
||||||
return []byte{hidLogicalMinimum + 1, uint8(min), uint8(min >> 8)}
|
case min < -32767 || 65535 < min:
|
||||||
|
return []byte{hidLogicalMinimum + hidSizeValue4, uint8(min), uint8(min >> 8), uint8(min >> 16), uint8(min >> 24)}
|
||||||
|
case min < -127 || 255 < min:
|
||||||
|
return []byte{hidLogicalMinimum + hidSizeValue2, uint8(min), uint8(min >> 8)}
|
||||||
|
default:
|
||||||
|
return []byte{hidLogicalMinimum + hidSizeValue1, byte(min)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []byte{hidLogicalMinimum, byte(min)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func HIDLogicalMaximum(max int) []byte {
|
func HIDLogicalMaximum(max int) []byte {
|
||||||
if max > 255 {
|
switch {
|
||||||
return []byte{hidLogicalMaximum + 1, uint8(max), uint8(max >> 8)}
|
case max < -32767 || 65535 < max:
|
||||||
|
return []byte{hidLogicalMaximum + hidSizeValue4, uint8(max), uint8(max >> 8), uint8(max >> 16), uint8(max >> 24)}
|
||||||
|
case max < -127 || 255 < max:
|
||||||
|
return []byte{hidLogicalMaximum + hidSizeValue2, uint8(max), uint8(max >> 8)}
|
||||||
|
default:
|
||||||
|
return []byte{hidLogicalMaximum + hidSizeValue1, byte(max)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []byte{hidLogicalMaximum, byte(max)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func HIDUsageMinimum(min int) []byte {
|
func HIDUsageMinimum(min int) []byte {
|
||||||
if min > 255 {
|
switch {
|
||||||
return []byte{hidUsageMinimum + 1, uint8(min), uint8(min >> 8)}
|
case min < -32767 || 65535 < min:
|
||||||
|
return []byte{hidUsageMinimum + hidSizeValue4, uint8(min), uint8(min >> 8), uint8(min >> 16), uint8(min >> 24)}
|
||||||
|
case min < -127 || 255 < min:
|
||||||
|
return []byte{hidUsageMinimum + hidSizeValue2, uint8(min), uint8(min >> 8)}
|
||||||
|
default:
|
||||||
|
return []byte{hidUsageMinimum + hidSizeValue1, byte(min)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []byte{hidUsageMinimum, byte(min)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func HIDUsageMaximum(max int) []byte {
|
func HIDUsageMaximum(max int) []byte {
|
||||||
if max > 255 {
|
switch {
|
||||||
return []byte{hidUsageMaximum + 1, uint8(max), uint8(max >> 8)}
|
case max < -32767 || 65535 < max:
|
||||||
|
return []byte{hidUsageMaximum + hidSizeValue4, uint8(max), uint8(max >> 8), uint8(max >> 16), uint8(max >> 24)}
|
||||||
|
case max < -127 || 255 < max:
|
||||||
|
return []byte{hidUsageMaximum + hidSizeValue2, uint8(max), uint8(max >> 8)}
|
||||||
|
default:
|
||||||
|
return []byte{hidUsageMaximum + hidSizeValue1, byte(max)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []byte{hidUsageMaximum, byte(max)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func HIDPhysicalMinimum(min int) []byte {
|
func HIDPhysicalMinimum(min int) []byte {
|
||||||
if min > 255 {
|
switch {
|
||||||
return []byte{hidPhysicalMinimum + 1, uint8(min), uint8(min >> 8)}
|
case min < -32767 || 65535 < min:
|
||||||
|
return []byte{hidPhysicalMinimum + hidSizeValue4, uint8(min), uint8(min >> 8), uint8(min >> 16), uint8(min >> 24)}
|
||||||
|
case min < -127 || 255 < min:
|
||||||
|
return []byte{hidPhysicalMinimum + hidSizeValue2, uint8(min), uint8(min >> 8)}
|
||||||
|
default:
|
||||||
|
return []byte{hidPhysicalMinimum + hidSizeValue1, byte(min)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []byte{hidPhysicalMinimum, byte(min)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func HIDPhysicalMaximum(max int) []byte {
|
func HIDPhysicalMaximum(max int) []byte {
|
||||||
if max > 255 {
|
switch {
|
||||||
return []byte{hidPhysicalMaximum + 1, uint8(max), uint8(max >> 8)}
|
case max < -32767 || 65535 < max:
|
||||||
|
return []byte{hidPhysicalMaximum + hidSizeValue4, uint8(max), uint8(max >> 8), uint8(max >> 16), uint8(max >> 24)}
|
||||||
|
case max < -127 || 255 < max:
|
||||||
|
return []byte{hidPhysicalMaximum + hidSizeValue2, uint8(max), uint8(max >> 8)}
|
||||||
|
default:
|
||||||
|
return []byte{hidPhysicalMaximum + hidSizeValue1, byte(max)}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []byte{hidPhysicalMaximum, byte(max)}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func HIDUnitExponent(exp int) []byte {
|
func HIDUnitExponent(exp int) []byte {
|
||||||
|
|||||||
@@ -80,10 +80,7 @@ var JoystickDefaultHIDReport = Append([][]byte{
|
|||||||
HIDLogicalMaximum(1),
|
HIDLogicalMaximum(1),
|
||||||
HIDReportSize(1),
|
HIDReportSize(1),
|
||||||
HIDReportCount(16),
|
HIDReportCount(16),
|
||||||
HIDInputDataVarAbs,
|
HIDUnitExponent(0),
|
||||||
HIDReportCount(1),
|
|
||||||
HIDReportSize(3),
|
|
||||||
HIDUnitExponent(-16),
|
|
||||||
HIDUnit(0),
|
HIDUnit(0),
|
||||||
HIDInputDataVarAbs,
|
HIDInputDataVarAbs,
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"machine"
|
"machine"
|
||||||
"machine/usb"
|
"machine/usb"
|
||||||
|
"machine/usb/descriptor"
|
||||||
)
|
)
|
||||||
|
|
||||||
// from usb-hid.go
|
// from usb-hid.go
|
||||||
@@ -22,7 +23,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type hidDevicer interface {
|
type hidDevicer interface {
|
||||||
Handler() bool
|
TxHandler() bool
|
||||||
|
RxHandler([]byte) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
var devices [5]hidDevicer
|
var devices [5]hidDevicer
|
||||||
@@ -32,19 +34,50 @@ var size int
|
|||||||
// calls machine.EnableHID for USB configuration
|
// calls machine.EnableHID for USB configuration
|
||||||
func SetHandler(d hidDevicer) {
|
func SetHandler(d hidDevicer) {
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
machine.EnableHID(handler, nil, setupHandler)
|
machine.ConfigureUSBEndpoint(descriptor.CDCHID,
|
||||||
|
[]usb.EndpointConfig{
|
||||||
|
{
|
||||||
|
Index: usb.HID_ENDPOINT_OUT,
|
||||||
|
IsIn: false,
|
||||||
|
Type: usb.ENDPOINT_TYPE_INTERRUPT,
|
||||||
|
RxHandler: rxHandler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Index: usb.HID_ENDPOINT_IN,
|
||||||
|
IsIn: true,
|
||||||
|
Type: usb.ENDPOINT_TYPE_INTERRUPT,
|
||||||
|
TxHandler: txHandler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]usb.SetupConfig{
|
||||||
|
{
|
||||||
|
Index: usb.HID_INTERFACE,
|
||||||
|
Handler: setupHandler,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
devices[size] = d
|
devices[size] = d
|
||||||
size++
|
size++
|
||||||
}
|
}
|
||||||
|
|
||||||
func handler() {
|
func txHandler() {
|
||||||
for _, d := range devices {
|
for _, d := range devices {
|
||||||
if d == nil {
|
if d == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if done := d.Handler(); done {
|
if done := d.TxHandler(); done {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func rxHandler(b []byte) {
|
||||||
|
for _, d := range devices {
|
||||||
|
if d == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if done := d.RxHandler(b); done {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package joystick
|
|||||||
import (
|
import (
|
||||||
"machine"
|
"machine"
|
||||||
"machine/usb"
|
"machine/usb"
|
||||||
|
"machine/usb/descriptor"
|
||||||
"machine/usb/hid"
|
"machine/usb/hid"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -32,18 +33,50 @@ func UseSettings(def Definitions, rxHandlerFunc func(b []byte), setupFunc func(s
|
|||||||
if setupFunc == nil {
|
if setupFunc == nil {
|
||||||
setupFunc = hid.DefaultSetupHandler
|
setupFunc = hid.DefaultSetupHandler
|
||||||
}
|
}
|
||||||
machine.EnableJoystick(js.handler, rxHandlerFunc, setupFunc, hidDesc)
|
if rxHandlerFunc == nil {
|
||||||
|
rxHandlerFunc = js.rxHandlerFunc
|
||||||
|
}
|
||||||
|
if len(hidDesc) == 0 {
|
||||||
|
hidDesc = descriptor.JoystickDefaultHIDReport
|
||||||
|
}
|
||||||
|
class, err := descriptor.FindClassHIDType(descriptor.CDCJoystick.Configuration, descriptor.ClassHIDJoystick.Bytes())
|
||||||
|
if err != nil {
|
||||||
|
// TODO: some way to notify about error
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
class.ClassLength(uint16(len(hidDesc)))
|
||||||
|
descriptor.CDCJoystick.HID[2] = hidDesc
|
||||||
|
|
||||||
|
machine.ConfigureUSBEndpoint(descriptor.CDCJoystick,
|
||||||
|
[]usb.EndpointConfig{
|
||||||
|
{
|
||||||
|
Index: usb.HID_ENDPOINT_OUT,
|
||||||
|
IsIn: false,
|
||||||
|
Type: usb.ENDPOINT_TYPE_INTERRUPT,
|
||||||
|
RxHandler: rxHandlerFunc,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Index: usb.HID_ENDPOINT_IN,
|
||||||
|
IsIn: true,
|
||||||
|
Type: usb.ENDPOINT_TYPE_INTERRUPT,
|
||||||
|
TxHandler: js.handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[]usb.SetupConfig{
|
||||||
|
{
|
||||||
|
Index: usb.HID_INTERFACE,
|
||||||
|
Handler: setupFunc,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
Joystick = js
|
Joystick = js
|
||||||
return js
|
return js
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDefaultJoystick() *joystick {
|
func newDefaultJoystick() *joystick {
|
||||||
def := DefaultDefinitions()
|
def := DefaultDefinitions()
|
||||||
js := &joystick{
|
js := UseSettings(def, nil, nil, nil)
|
||||||
State: def.NewState(),
|
|
||||||
buf: hid.NewRingBuffer(),
|
|
||||||
}
|
|
||||||
machine.EnableJoystick(js.handler, js.rxHandler, hid.DefaultSetupHandler, def.Descriptor())
|
|
||||||
return js
|
return js
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func newKeyboard() *keyboard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (kb *keyboard) Handler() bool {
|
func (kb *keyboard) TxHandler() bool {
|
||||||
kb.waitTxc = false
|
kb.waitTxc = false
|
||||||
if b, ok := kb.buf.Get(); ok {
|
if b, ok := kb.buf.Get(); ok {
|
||||||
kb.waitTxc = true
|
kb.waitTxc = true
|
||||||
@@ -91,6 +91,13 @@ func (kb *keyboard) Handler() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) RxHandler(b []byte) bool {
|
||||||
|
if len(b) >= 2 && b[0] == 2 /* ReportID */ {
|
||||||
|
kb.led = b[1]
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (kb *keyboard) tx(b []byte) {
|
func (kb *keyboard) tx(b []byte) {
|
||||||
if machine.USBDev.InitEndpointComplete {
|
if machine.USBDev.InitEndpointComplete {
|
||||||
if kb.waitTxc {
|
if kb.waitTxc {
|
||||||
@@ -102,6 +109,18 @@ func (kb *keyboard) tx(b []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) NumLockLed() bool {
|
||||||
|
return kb.led&1 != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) CapsLockLed() bool {
|
||||||
|
return kb.led&2 != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (kb *keyboard) ScrollLockLed() bool {
|
||||||
|
return kb.led&4 != 0
|
||||||
|
}
|
||||||
|
|
||||||
func (kb *keyboard) ready() bool {
|
func (kb *keyboard) ready() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func newMouse() *mouse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mouse) Handler() bool {
|
func (m *mouse) TxHandler() bool {
|
||||||
m.waitTxc = false
|
m.waitTxc = false
|
||||||
if b, ok := m.buf.Get(); ok {
|
if b, ok := m.buf.Get(); ok {
|
||||||
m.waitTxc = true
|
m.waitTxc = true
|
||||||
@@ -57,6 +57,10 @@ func (m *mouse) Handler() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *mouse) RxHandler(b []byte) bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (m *mouse) tx(b []byte) {
|
func (m *mouse) tx(b []byte) {
|
||||||
if machine.USBDev.InitEndpointComplete {
|
if machine.USBDev.InitEndpointComplete {
|
||||||
if m.waitTxc {
|
if m.waitTxc {
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
//go:build nrf52840 || nrf52833 || rp2040 || atsamd51 || atsame5x || stm32
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
// WatchdogConfig holds configuration for the watchdog timer.
|
||||||
|
type WatchdogConfig struct {
|
||||||
|
// The timeout (in milliseconds) before the watchdog fires.
|
||||||
|
//
|
||||||
|
// If the requested timeout exceeds `MaxTimeout` it will be rounded
|
||||||
|
// down.
|
||||||
|
TimeoutMillis uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
// watchdog must be implemented by any platform supporting watchdog functionality
|
||||||
|
type watchdog interface {
|
||||||
|
// Configure the watchdog.
|
||||||
|
//
|
||||||
|
// This method should not be called after the watchdog is started and on
|
||||||
|
// some platforms attempting to reconfigure after starting the watchdog
|
||||||
|
// is explicitly forbidden / will not work.
|
||||||
|
Configure(config WatchdogConfig) error
|
||||||
|
|
||||||
|
// Starts the watchdog.
|
||||||
|
Start() error
|
||||||
|
|
||||||
|
// Update the watchdog, indicating that the app is healthy.
|
||||||
|
Update()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure required public symbols var exists and meets interface spec
|
||||||
|
var _ = watchdog(Watchdog)
|
||||||
|
|
||||||
|
// Ensure required public constants exist
|
||||||
|
const _ = WatchdogMaxTimeout
|
||||||
+1
-1
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build linux && !baremetal && !wasi
|
//go:build linux && !baremetal && !wasi && !wasip1
|
||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
|
|||||||
+1
-4
@@ -6,7 +6,7 @@
|
|||||||
// fairly similar: we use fdopendir, fdclosedir, and readdir from wasi-libc in
|
// fairly similar: we use fdopendir, fdclosedir, and readdir from wasi-libc in
|
||||||
// a similar way that the darwin code uses functions from libc.
|
// a similar way that the darwin code uses functions from libc.
|
||||||
|
|
||||||
//go:build wasi
|
//go:build wasi || wasip1
|
||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
@@ -53,9 +53,6 @@ func (f *File) readdir(n int, mode readdirMode) (names []string, dirents []DirEn
|
|||||||
if dirent == nil { // EOF
|
if dirent == nil { // EOF
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if dirent.Ino == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
name := dirent.Name()
|
name := dirent.Name()
|
||||||
// Check for useless names before allocating a string.
|
// Check for useless names before allocating a string.
|
||||||
if string(name) == "." || string(name) == ".." {
|
if string(name) == "." || string(name) == ".." {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build darwin || linux
|
//go:build darwin || linux || wasip1
|
||||||
|
|
||||||
package os_test
|
package os_test
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,10 @@ var (
|
|||||||
// The following code is copied from the official implementation.
|
// The following code is copied from the official implementation.
|
||||||
// src/internal/poll/fd.go
|
// src/internal/poll/fd.go
|
||||||
|
|
||||||
|
// ErrNoDeadline is returned when a request is made to set a deadline
|
||||||
|
// on a file type that does not use the poller.
|
||||||
|
var ErrNoDeadline = errors.New("file type does not support deadline")
|
||||||
|
|
||||||
// ErrDeadlineExceeded is returned for an expired deadline.
|
// ErrDeadlineExceeded is returned for an expired deadline.
|
||||||
// This is exported by the os package as os.ErrDeadlineExceeded.
|
// This is exported by the os package as os.ErrDeadlineExceeded.
|
||||||
var ErrDeadlineExceeded error = &DeadlineExceededError{}
|
var ErrDeadlineExceeded error = &DeadlineExceededError{}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
|
//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || wasip1 || windows
|
||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build baremetal || (wasm && !wasi)
|
//go:build baremetal || (wasm && !wasi && !wasip1)
|
||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
//go:build darwin || (linux && !baremetal)
|
//go:build darwin || (linux && !baremetal) || wasip1
|
||||||
|
|
||||||
// target wasi sets GOOS=linux and thus the +linux build tag,
|
// target wasi sets GOOS=linux and thus the +linux build tag,
|
||||||
// even though it doesn't show up in "tinygo info target -wasi"
|
// even though it doesn't show up in "tinygo info target -wasi"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build windows || darwin || (linux && !baremetal)
|
//go:build windows || darwin || (linux && !baremetal) || wasip1
|
||||||
|
|
||||||
package os_test
|
package os_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !wasi
|
//go:build !wasi && !wasip1
|
||||||
|
|
||||||
package os_test
|
package os_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build wasi
|
//go:build wasi || wasip1
|
||||||
|
|
||||||
package os_test
|
package os_test
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build windows || darwin || (linux && !baremetal)
|
//go:build windows || darwin || (linux && !baremetal) || wasip1
|
||||||
|
|
||||||
package os_test
|
package os_test
|
||||||
|
|
||||||
@@ -23,7 +23,6 @@ var dot = []string{
|
|||||||
"os_test.go",
|
"os_test.go",
|
||||||
"types.go",
|
"types.go",
|
||||||
"stat_darwin.go",
|
"stat_darwin.go",
|
||||||
"stat_linux.go",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func randomName() string {
|
func randomName() string {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !baremetal && !js && !wasi
|
//go:build !baremetal && !js && !wasi && !wasip1
|
||||||
|
|
||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !windows && !baremetal && !js && !wasi
|
//go:build !windows && !baremetal && !js && !wasi && !wasip1
|
||||||
|
|
||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
//go:build !baremetal && !js && !wasi
|
//go:build !baremetal && !js && !wasi && !wasip1
|
||||||
|
|
||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build !baremetal && !js && !wasi
|
//go:build !baremetal && !js && !wasi && !wasip1
|
||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build baremetal || js || wasi
|
//go:build baremetal || js || wasi || wasip1
|
||||||
|
|
||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
//go:build linux && !baremetal
|
//go:build (linux && !baremetal) || wasip1
|
||||||
|
|
||||||
// Copyright 2009 The Go Authors. All rights reserved.
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Note: this file is used for both Linux and WASI.
|
||||||
|
// Eventually it might be better to spit it up, and make the syscall constants
|
||||||
|
// match the typical WASI constants instead of the Linux-equivalents used here.
|
||||||
|
|
||||||
package os
|
package os
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build baremetal || (wasm && !wasi)
|
//go:build baremetal || (wasm && !wasi && !wasip1)
|
||||||
|
|
||||||
// Copyright 2016 The Go Authors. All rights reserved.
|
// Copyright 2016 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user