mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 14:48:40 +00:00
Compare commits
146 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b49f583ab7 | |||
| 7ec9cfc61c | |||
| 294cf28e43 | |||
| 2f7a66e6d3 | |||
| a4f9c9d1b6 | |||
| aa10b682e4 | |||
| eafbe4ee69 | |||
| cf5912412d | |||
| 1f114b2acf | |||
| 94ebddbdfe | |||
| aa1ca27789 | |||
| 9999320cd0 | |||
| 74429b4a14 | |||
| bcb191c01e | |||
| ddb848816f | |||
| 889911d0a6 | |||
| a4dd38de81 | |||
| 486ee37a40 | |||
| 944176beef | |||
| c396418187 | |||
| 1b4ab772d2 | |||
| aca0fe0412 | |||
| af511c1118 | |||
| 5ba8766cbc | |||
| b792c10680 | |||
| 12d41ba0c1 | |||
| 020cca8c3c | |||
| 4cbd34d32f | |||
| 6426bf79b4 | |||
| aed8116b22 | |||
| f6c759ccbf | |||
| 4b389b90e8 | |||
| 4c3680635e | |||
| 0755145824 | |||
| eabd1ddce0 | |||
| 0e84235f9a | |||
| 894839484c | |||
| 1fadd0e772 | |||
| eba6e7a428 | |||
| f4a6e0373b | |||
| d274545e63 | |||
| f74d25c882 | |||
| 618c689246 | |||
| 9d29971755 | |||
| 451c57af92 | |||
| 59feac28b9 | |||
| c1f48fc79a | |||
| 3c07a36e95 | |||
| 98b3c27c76 | |||
| ddacdfacd5 | |||
| 2d477e069d | |||
| ed1a56785a | |||
| f496571747 | |||
| 17fed5980b | |||
| 2ff04f1a87 | |||
| f763865c5c | |||
| 52edf52245 | |||
| 8161b766d3 | |||
| 709349e24b | |||
| 5fd4878574 | |||
| a24dc8c543 | |||
| c3d514a751 | |||
| 5b7a2c73db | |||
| aaf6a36c55 | |||
| dc6e0e23b9 | |||
| 44b0c79eaf | |||
| 27e5baeb57 | |||
| a6a4f85e61 | |||
| 3386316b9f | |||
| 410bb9c103 | |||
| f176b3a480 | |||
| 9b1a3a2236 | |||
| b29edadf48 | |||
| d04332d688 | |||
| 547288529c | |||
| bd8de8719f | |||
| 2fd44ac341 | |||
| dc30aef687 | |||
| 29cadaa23b | |||
| a7c149f8dc | |||
| c2a04e1a45 | |||
| f748dc6fd8 | |||
| bfc21ad906 | |||
| 41726fab9d | |||
| 82f4fcf2a3 | |||
| 3a00f00f62 | |||
| a71f776203 | |||
| d2f60c02bb | |||
| 7ca53138bc | |||
| a9c0501826 | |||
| 60fb4b95fa | |||
| 323b62b405 | |||
| 40fb3466c1 | |||
| 2333ef2454 | |||
| 0ac7bf8c8b | |||
| 38a3ccee52 | |||
| 47115f0380 | |||
| 1f00425eb3 | |||
| 71245845c8 | |||
| d9f6f3b81f | |||
| b81a7c2bca | |||
| 0ec2f0818a | |||
| 4a6a82ae79 | |||
| b14ee51ff6 | |||
| 394116e998 | |||
| f902437848 | |||
| 86cc3b6c12 | |||
| 6bb6ea2432 | |||
| 3c590e36ad | |||
| 69a4dda8c8 | |||
| 8fbaffe56e | |||
| bfafef8df1 | |||
| 26ff622148 | |||
| 88a68eaf7e | |||
| 46a2a177c1 | |||
| b0ea05a853 | |||
| f3b79c412f | |||
| f4f3ad5051 | |||
| 0757ccc657 | |||
| 47282be619 | |||
| 9bdbe943ce | |||
| 180220a2e3 | |||
| 8ef4af45d7 | |||
| 9215aa7ece | |||
| b497c5da71 | |||
| bf4d2fef4a | |||
| c053b8fc8a | |||
| d364ac6024 | |||
| d78be5112b | |||
| b5233eea56 | |||
| 09a6612742 | |||
| 1778ad620f | |||
| 458b50bc07 | |||
| fca8784dc3 | |||
| a846ee2321 | |||
| df087b592f | |||
| eade931650 | |||
| a7649f5b42 | |||
| f0b953dec9 | |||
| bb8196653f | |||
| a1b44ddd58 | |||
| 48b0d7f434 | |||
| d8b6b257f4 | |||
| c98972a3e0 | |||
| b93759936c | |||
| d62dda8140 |
@@ -96,7 +96,7 @@ jobs:
|
||||
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
||||
# least the smoke tests still pass.
|
||||
docker:
|
||||
- image: golang:1.22-bullseye
|
||||
- image: golang:1.23-bullseye
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "15"
|
||||
@@ -105,7 +105,7 @@ jobs:
|
||||
# This tests the latest supported LLVM version when linking against system
|
||||
# libraries.
|
||||
docker:
|
||||
- image: golang:1.25-bullseye
|
||||
- image: golang:1.26-bookworm
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "20"
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
run: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Extract TinyGo version
|
||||
@@ -40,10 +40,10 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: '1.26.2'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-${{ matrix.os }}-v1
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-20-${{ matrix.os }}-v2
|
||||
@@ -85,7 +85,7 @@ jobs:
|
||||
make llvm-build
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
@@ -101,16 +101,11 @@ jobs:
|
||||
- name: Make release artifact
|
||||
run: cp -p build/release.tar.gz build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz
|
||||
- name: Publish release artifact
|
||||
# Note: this release artifact is double-zipped, see:
|
||||
# https://github.com/actions/upload-artifact/issues/39
|
||||
# We can essentially pick one of these:
|
||||
# - have a double-zipped artifact when downloaded from the UI
|
||||
# - have a very slow artifact upload
|
||||
# We're doing the former here, to keep artifact uploads fast.
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: darwin-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }}
|
||||
path: build/tinygo${{ steps.version.outputs.version }}.darwin-${{ matrix.goarch }}.tar.gz
|
||||
archive: false
|
||||
- name: Smoke tests
|
||||
run: make smoketest TINYGO=$(PWD)/build/tinygo
|
||||
test-macos-homebrew:
|
||||
@@ -121,7 +116,7 @@ jobs:
|
||||
version: [16, 17, 18, 19, 20]
|
||||
steps:
|
||||
- name: Set up Homebrew
|
||||
uses: Homebrew/actions/setup-homebrew@master
|
||||
uses: Homebrew/actions/setup-homebrew@main
|
||||
- name: Fix Python symlinks
|
||||
run: |
|
||||
# Github runners have broken symlinks, so relink
|
||||
@@ -130,12 +125,13 @@ jobs:
|
||||
- name: Install LLVM
|
||||
run: |
|
||||
brew install llvm@${{ matrix.version }}
|
||||
brew link llvm@${{ matrix.version }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: '1.26.2'
|
||||
cache: true
|
||||
- name: Build TinyGo (LLVM ${{ matrix.version }})
|
||||
run: go install -tags=llvm${{ matrix.version }}
|
||||
|
||||
@@ -31,14 +31,14 @@ jobs:
|
||||
sudo rm -rf /usr/local/share/boost
|
||||
df -h
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: |
|
||||
tinygo/tinygo-dev
|
||||
@@ -47,18 +47,18 @@ jobs:
|
||||
type=sha,format=long
|
||||
type=raw,value=latest
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
- name: Log in to Github Container Registry
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
|
||||
+58
-48
@@ -18,12 +18,12 @@ jobs:
|
||||
# statically linked binary.
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: golang:1.25-alpine
|
||||
image: golang:1.26-alpine
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
- name: Install apk dependencies
|
||||
# tar: needed for actions/cache@v4
|
||||
# tar: needed for actions/cache@v5
|
||||
# git+openssh: needed for checkout (I think?)
|
||||
# ruby: needed to install fpm
|
||||
run: apk add tar git openssh make g++ ruby-dev mold
|
||||
@@ -31,24 +31,24 @@ jobs:
|
||||
# We're not on a multi-user machine, so this is safe.
|
||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Extract TinyGo version
|
||||
id: version
|
||||
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
|
||||
key: go-cache-linux-alpine-v2-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-linux-alpine-v1
|
||||
key: llvm-source-20-linux-alpine-v2
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -70,10 +70,10 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-20-linux-alpine-v1
|
||||
key: llvm-build-20-linux-alpine-v2
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -88,16 +88,16 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-alpine-v1
|
||||
key: binaryen-linux-alpine-v2
|
||||
path: build/wasm-opt
|
||||
- name: Build Binaryen
|
||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
||||
@@ -118,26 +118,31 @@ jobs:
|
||||
make release deb -j3 STATIC=1
|
||||
cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
|
||||
cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
|
||||
- name: Publish release artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
- name: "Publish release artifact: tarball"
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: linux-amd64-double-zipped-${{ steps.version.outputs.version }}
|
||||
path: |
|
||||
/tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
|
||||
/tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
|
||||
name: tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
|
||||
path: /tmp/tinygo${{ steps.version.outputs.version }}.linux-amd64.tar.gz
|
||||
archive: false
|
||||
- name: "Publish release artifact: Debian package"
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: tinygo_${{ steps.version.outputs.version }}_amd64.deb
|
||||
path: /tmp/tinygo_${{ steps.version.outputs.version }}_amd64.deb
|
||||
archive: false
|
||||
test-linux-build:
|
||||
# Test the binaries built in the build-linux job by running the smoke tests.
|
||||
runs-on: ubuntu-latest
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: '1.26.2'
|
||||
cache: true
|
||||
- name: Install wasmtime
|
||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||
@@ -146,9 +151,9 @@ jobs:
|
||||
- name: Install wasm-tools
|
||||
uses: bytecodealliance/actions/wasm-tools/setup@v1
|
||||
- name: Download release artifact
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }}
|
||||
name: tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz
|
||||
- name: Extract release tarball
|
||||
run: |
|
||||
mkdir -p ~/lib
|
||||
@@ -164,7 +169,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Install apt dependencies
|
||||
@@ -181,10 +186,10 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: '1.26.2'
|
||||
cache: true
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '18'
|
||||
- name: Install wasmtime
|
||||
@@ -194,7 +199,7 @@ jobs:
|
||||
- name: Setup `wasm-tools`
|
||||
uses: bytecodealliance/actions/wasm-tools/setup@v1
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-linux-asserts-v1
|
||||
@@ -208,7 +213,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -219,7 +224,7 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-20-linux-asserts-v1
|
||||
@@ -235,13 +240,13 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-asserts-v1
|
||||
@@ -284,7 +289,7 @@ jobs:
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: Get TinyGo version
|
||||
id: version
|
||||
run: ./.github/workflows/tinygo-extract-version.sh | tee -a "$GITHUB_OUTPUT"
|
||||
@@ -298,10 +303,10 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: '1.26.2'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-linux-v1
|
||||
@@ -315,7 +320,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -326,7 +331,7 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore LLVM build cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-20-linux-${{ matrix.goarch }}-v1
|
||||
@@ -344,13 +349,13 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save LLVM build cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-${{ matrix.goarch }}-v4
|
||||
@@ -370,9 +375,9 @@ jobs:
|
||||
run: |
|
||||
make CROSS=${{ matrix.toolchain }}
|
||||
- name: Download amd64 release
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: linux-amd64-double-zipped-${{ needs.build-linux.outputs.version }}
|
||||
name: tinygo${{ needs.build-linux.outputs.version }}.linux-amd64.tar.gz
|
||||
- name: Extract amd64 release
|
||||
run: |
|
||||
mkdir -p build/release
|
||||
@@ -384,12 +389,17 @@ jobs:
|
||||
- name: Create ${{ matrix.goarch }} release
|
||||
run: |
|
||||
make release deb RELEASEONLY=1 DEB_ARCH=${{ matrix.libc }}
|
||||
cp -p build/release.tar.gz /tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
|
||||
cp -p build/release.deb /tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb
|
||||
- name: Publish release artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
cp -p build/release.tar.gz /tmp/tinygo${{ needs.build-linux.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
|
||||
cp -p build/release.deb /tmp/tinygo_${{ needs.build-linux.outputs.version }}_${{ matrix.libc }}.deb
|
||||
- name: "Publish release artifact: tarball"
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: linux-${{ matrix.goarch }}-double-zipped-${{ steps.version.outputs.version }}
|
||||
path: |
|
||||
/tmp/tinygo${{ steps.version.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
|
||||
/tmp/tinygo_${{ steps.version.outputs.version }}_${{ matrix.libc }}.deb
|
||||
name: linux-${{ matrix.goarch }}-double-zipped-${{ needs.build-linux.outputs.version }}
|
||||
path: /tmp/tinygo${{ needs.build-linux.outputs.version }}.linux-${{ matrix.goarch }}.tar.gz
|
||||
archive: false
|
||||
- name: "Publish release artifact: Debian package"
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: linux-${{ matrix.goarch }}-double-zipped-${{ needs.build-linux.outputs.version }}
|
||||
path: /tmp/tinygo_${{ needs.build-linux.outputs.version }}_${{ matrix.libc }}.deb
|
||||
archive: false
|
||||
|
||||
@@ -25,14 +25,14 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@v4
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: |
|
||||
tinygo/llvm-20
|
||||
@@ -46,13 +46,13 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
- name: Log in to Github Container Registry
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
target: tinygo-llvm-build
|
||||
context: .
|
||||
|
||||
@@ -21,12 +21,12 @@ jobs:
|
||||
# See: https://github.com/tinygo-org/tinygo/pull/4516#issuecomment-2416363668
|
||||
run: sudo apt-get remove llvm-18
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: Pull musl, bdwgc
|
||||
run: |
|
||||
git submodule update --init lib/musl lib/bdwgc
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-linux-nix-v1
|
||||
@@ -36,13 +36,13 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save LLVM source cache
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
path: |
|
||||
llvm-project/compiler-rt
|
||||
- uses: cachix/install-nix-action@v22
|
||||
- uses: cachix/install-nix-action@v31
|
||||
- name: Test
|
||||
run: |
|
||||
nix develop --ignore-environment --keep HOME --command bash -c "go install && ~/go/bin/tinygo version && ~/go/bin/tinygo build -o test ./testdata/cgo"
|
||||
|
||||
@@ -20,14 +20,14 @@ jobs:
|
||||
run: |
|
||||
echo "$HOME/go/bin" >> $GITHUB_PATH
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0 # fetch all history (no sparse checkout)
|
||||
submodules: true
|
||||
- name: Install apt dependencies
|
||||
run: ./.github/workflows/sizediff-install-pkgs.sh
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-sizediff-v1
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
key: go-cache-linux-sizediff-v2-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
|
||||
@@ -24,14 +24,13 @@ jobs:
|
||||
maximum-size: 24GB
|
||||
disk-root: "C:"
|
||||
- uses: MinoruSekine/setup-scoop@v4
|
||||
with:
|
||||
scoop_update: 'false'
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
scoop config use_external_7zip true
|
||||
scoop install ninja binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: true
|
||||
- name: Extract TinyGo version
|
||||
@@ -41,10 +40,10 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: '1.26.2'
|
||||
cache: true
|
||||
- name: Restore cached LLVM source
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-20-windows-v1
|
||||
@@ -58,7 +57,7 @@ jobs:
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Save cached LLVM source
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||
@@ -69,7 +68,7 @@ jobs:
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Restore cached LLVM build
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-20-windows-v2
|
||||
@@ -86,20 +85,21 @@ jobs:
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Save cached LLVM build
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@v5
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
with:
|
||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||
path: llvm-build
|
||||
- name: Cache Go cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
key: go-cache-windows-v1-${{ hashFiles('go.mod') }}
|
||||
key: go-cache-windows-v2-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
C:/Users/runneradmin/AppData/Local/go-build
|
||||
C:/Users/runneradmin/go/pkg/mod
|
||||
- name: Install wasmtime
|
||||
run: |
|
||||
scoop config use_external_7zip true
|
||||
scoop install wasmtime@29.0.1
|
||||
- name: make gen-device
|
||||
run: make -j3 gen-device
|
||||
@@ -114,16 +114,11 @@ jobs:
|
||||
working-directory: build/release
|
||||
run: 7z -tzip a tinygo${{ steps.version.outputs.version }}.windows-amd64.zip tinygo
|
||||
- name: Publish release artifact
|
||||
# Note: this release artifact is double-zipped, see:
|
||||
# https://github.com/actions/upload-artifact/issues/39
|
||||
# We can essentially pick one of these:
|
||||
# - have a dobule-zipped artifact when downloaded from the UI
|
||||
# - have a very slow artifact upload
|
||||
# We're doing the former here, to keep artifact uploads fast.
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: windows-amd64-double-zipped-${{ steps.version.outputs.version }}
|
||||
name: tinygo${{ steps.version.outputs.version }}.windows-amd64.zip
|
||||
path: build/release/tinygo${{ steps.version.outputs.version }}.windows-amd64.zip
|
||||
archive: false
|
||||
|
||||
smoke-test-windows:
|
||||
runs-on: windows-2022
|
||||
@@ -136,28 +131,24 @@ jobs:
|
||||
maximum-size: 24GB
|
||||
disk-root: "C:"
|
||||
- uses: MinoruSekine/setup-scoop@v4
|
||||
with:
|
||||
scoop_update: 'false'
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
scoop config use_external_7zip true
|
||||
scoop install binaryen
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: '1.26.2'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
|
||||
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip
|
||||
path: build/
|
||||
- name: Unzip TinyGo build
|
||||
shell: bash
|
||||
working-directory: build
|
||||
run: 7z x tinygo*.windows-amd64.zip -r
|
||||
# This build is already unzipped.
|
||||
- name: Smoke tests
|
||||
shell: bash
|
||||
run: make smoketest TINYGO=$(PWD)/build/tinygo/bin/tinygo
|
||||
@@ -173,21 +164,18 @@ jobs:
|
||||
maximum-size: 24GB
|
||||
disk-root: "C:"
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: '1.26.2'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
|
||||
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip
|
||||
path: build/
|
||||
- name: Unzip TinyGo build
|
||||
shell: bash
|
||||
working-directory: build
|
||||
run: 7z x tinygo*.windows-amd64.zip -r
|
||||
# This build is already unzipped.
|
||||
- name: Test stdlib packages
|
||||
run: make tinygo-test TINYGO=$(PWD)/build/tinygo/bin/tinygo
|
||||
|
||||
@@ -202,27 +190,23 @@ jobs:
|
||||
maximum-size: 24GB
|
||||
disk-root: "C:"
|
||||
- uses: MinoruSekine/setup-scoop@v4
|
||||
with:
|
||||
scoop_update: 'false'
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
scoop install binaryen && scoop install wasmtime@29.0.1
|
||||
scoop config use_external_7zip true
|
||||
scoop install binaryen wasmtime@29.0.1
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: '1.26.2'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: windows-amd64-double-zipped-${{ needs.build-windows.outputs.version }}
|
||||
name: tinygo${{ needs.build-windows.outputs.version }}.windows-amd64.zip
|
||||
path: build/
|
||||
- name: Unzip TinyGo build
|
||||
shell: bash
|
||||
working-directory: build
|
||||
run: 7z x tinygo*.windows-amd64.zip -r
|
||||
# This build is already unzipped.
|
||||
- name: Test stdlib packages on wasip1
|
||||
run: make tinygo-test-wasip1-fast TINYGO=$(PWD)/build/tinygo/bin/tinygo
|
||||
|
||||
+157
@@ -1,3 +1,160 @@
|
||||
0.41.1
|
||||
---
|
||||
* **machine**
|
||||
- esp32c3: correct pin interrupt setup call that was overlooked from #5320
|
||||
* **runtime**
|
||||
- esp32s3: wait for TIMG0 update register to clear before reading timer registers
|
||||
* **net**
|
||||
- update net module to a version that is backwards compatible with Go 1.25.x to fix #5332
|
||||
|
||||
0.41.0
|
||||
---
|
||||
* **general**
|
||||
- go.mod, compiler: bump minimum Go version to 1.23
|
||||
- builder: support Go 1.26 now
|
||||
- feat: add inheritable-only field to filter processor-level targets (#5270)
|
||||
- feature: add esp32flash flash method for esp32s3/esp32c3/esp32/esp8266
|
||||
- flashing: introduce flash method 'esp32jtag' for esp32c3/esp32s3 targets
|
||||
- fashing: add "adb" flash method using Android Debug Bridge
|
||||
- main: auto-use best available flashing options on esp32
|
||||
- espflasher: update to espflasher 0.6.0
|
||||
* **compiler**
|
||||
- implement method-set based AssignableTo and Implements (#5304)
|
||||
- simplify createObjectLayout
|
||||
- implement copy directly
|
||||
- fix min/max on floats by using intrinsics
|
||||
- add element layout to sliceAppend
|
||||
- add intrinsic for crypto/internal/constanttime.boolToUint8
|
||||
- fix SyscallN handling for Windows on Go 1.26+
|
||||
* **core**
|
||||
- reflect: add TypeAssert
|
||||
- reflect: fix TypeAssert for structs
|
||||
- sync: add WaitGroup.Go
|
||||
- os: add UserCacheDir and UserConfigDir
|
||||
- os: implement Lchown function for changing file ownership (#5161)
|
||||
- testing: add b.ReportMetric()
|
||||
- errors: add errors package to passing list
|
||||
- internal/gclayout: use correct lengths
|
||||
- internal/abi: add EscapeNonString, EscapeToResultNonString
|
||||
- internal, runtime: add internal fips bool
|
||||
- internal/itoa: resurrect from Go stdlib
|
||||
- internal/syscall/unix: implement GetRandom for WASI targets
|
||||
- interp: make ptrtoint size mismatch a recoverable error
|
||||
- loader: support "all:" prefix in //go:embed patterns
|
||||
- loader, crypto/internal/entropy: fix 32 MiB RAM overflow on microcontrollers
|
||||
- loader, unicode/utf8: fix hiBits overflow on 16-bit AVR targets
|
||||
- builder: order embedded files deterministically
|
||||
- builder: fix panic in findPackagePath when using -size short
|
||||
- builder: fix SIGSEGV when stripping duplicate function definitions
|
||||
- builder, runtime: fix duplicate symbol error with Go 1.26+ on Windows
|
||||
- builder: use target-specific -march for RISC-V library compilation
|
||||
- transform: modify output format from the -print-allocs flag to match the go coverage tool format
|
||||
- cgo: allow for changes to 'short-enums' flag
|
||||
- wasm: add more stubbed file operations
|
||||
* **machine**
|
||||
- esp32c3: implement BlockDevice for esp32c3 flash
|
||||
- esp32c3: clear GPIO STATUS before dispatching pin callbacks
|
||||
- esp32c3: implement USBDevice using interrupts
|
||||
- esp32c3: add Enable stub for QEMU test target
|
||||
- esp32c3: fix interrupt disable handling
|
||||
- esp32c3: clear MCAUSE after handling interrupt
|
||||
- esp32c3: map missing IRAM sections in linker script
|
||||
- esp32c3: fix to use PROVIDE() for WiFi/BLE ROM function addresses to allow blob overrides
|
||||
- esp32c3: add WiFi/BLE ROM linker support
|
||||
- esp32c3: use TIMG0 alarm interrupt for sleepTicks instead of busy-waiting
|
||||
- esp32s3: implement Pin.SetInterrupt for GPIO pin change interrupts
|
||||
- esp32s3: use edge-triggered CPU interrupt for GPIO pin interrupts
|
||||
- esp32s3: add interrupt support (#5244)
|
||||
- esp32s3: switch USB implementation to use interrupts instead of polling
|
||||
- esp32s3: replace inline ISR with full interrupt vector handler
|
||||
- esp32s3: use TIMG0 alarm interrupt for sleepTicks
|
||||
- esp32s3: improve exception handlers, add procPin/procUnpin, and linker wrap flags
|
||||
- esp32s3: fix Xtensa register window spill using recursive call4 in task switching
|
||||
- esp32s3: update linker script and boot assembly for multi-page flash XIP mapping
|
||||
- esp32s3: add flash XIP boot assembly with cache/MMU init
|
||||
- esp32s3: implement SPI (#5169)
|
||||
- esp32s3: implement I2C interface (#5210)
|
||||
- esp32s3: implement RNG based on onboard hardware random number generator
|
||||
- esp32s3,esp32c3: add USB serial support
|
||||
- esp32s3,esp32c3: add txStalled flag to skip USB serial spin when no host
|
||||
- esp32s3,esp32c3: make USB Serial/JTAG writes non-blocking when FIFO is full
|
||||
- esp32c3/esp32s3: refactor ADC implementation to reduce code duplication
|
||||
- esp32s3,esp32c3: add ADC support (#5231)
|
||||
- esp32s3,esp32c3: add PWM support (#5215)
|
||||
- esp32c3/esp32s3: refactoring and corrections for SPI implementation
|
||||
- esp32xx: add WASM simulator support for ESP32-C3/ESP32-S3 targets
|
||||
- esp32: default SPI CS pin to NoPin when unset
|
||||
- esp: fix tinygo_scanCurrentStack to spill register windows
|
||||
- stm32: fix UART interrupt storm caused by uncleared overrun error
|
||||
- stm32: fix PWM problem due to register shifting
|
||||
- stm32: add STM32U585 target definition and runtime
|
||||
- stm32: add STM32U5 GPIO, pin interrupts, and UART support
|
||||
- stm32: add STM32U5 I2C support
|
||||
- stm32: add STM32U5 SPI support
|
||||
- stm32u585: implement ADC
|
||||
- stm32g0b1: add support (#5150)
|
||||
- stm32g0b1: add Watchdog + ADC support (#5158)
|
||||
- stm32l0: add flash support
|
||||
- stm32l0x1,l0x2: TIM: adapt to 32-bit register access
|
||||
- stm32g0: sync with updated stm32 device files
|
||||
- attiny85: add USI-based SPI support (#5181)
|
||||
- attiny85: add PWM support (#5171)
|
||||
- rp: add Close function to UART to allow for removing all system resources/power usage
|
||||
- rp: use blockReset() and unresetBlockWait() helper functions for peripheral reset/unreset
|
||||
- rp2: prevent PWM Period method overflow
|
||||
- rp2: add per-byte timeout budget for I2C (#5189)
|
||||
- feather-m0: export UART0 and pins
|
||||
- usb/cdc: better ring buffer implementation (#5209)
|
||||
- fix: replace ! with ~ for register mask
|
||||
- atmega328p_simulator: add correct build tag for arduino_uno after renaming
|
||||
* **net**
|
||||
- update to Go 1.26.2 net package with UDP and JS improvements
|
||||
* **runtime**
|
||||
- implement fminimum/fmaximum
|
||||
- make timeoffset atomic
|
||||
- add MemStats.HeapObjects
|
||||
- handle GODEBUG on wasip2 (#5312)
|
||||
- fix Darwin syscall return value truncation and lost arguments
|
||||
- add syscall.runtimeClearenv for Go 1.26
|
||||
- split syscall functions for darwin changes for 1.26
|
||||
- fix: init heap before random number seed on wasm platforms
|
||||
* **targets**
|
||||
- add esp32s3-supermini board target
|
||||
- add support for Seeedstudio Xiao-RP2350 board
|
||||
- add Shrike Lite board (#5170)
|
||||
- rename arduino target to arduino-uno
|
||||
- add pins/setup for Arduino UNO Q board QWIIC connector
|
||||
- correct pin mapping for Arduino UNO Q STM32 MCU
|
||||
- add stm32u585 openocd commands for flashing on Arduino UNO Q
|
||||
- correct name/tag use for esp32s3-wroom1 board
|
||||
- modify esp32, esp32s3, esp32c3, & esp8266 targets to use built-in esp32flash
|
||||
- switch rp2040/rp2350 to default to tasks scheduler
|
||||
- change default stack size for esp32c3 and esp32s3 to 8196
|
||||
- swan: rename group build tag stm32l4x5 => stm32l4y5 to avoid clash with stm32 device name
|
||||
- nucleo-f722ze: add build-tag stm32f722
|
||||
- fix: set stm32u5x clock rate to default
|
||||
- create generic targets for esp32 boards
|
||||
* **libs**
|
||||
- stm32-svd: update submodule
|
||||
- update tools/gen-device-svd for recent changes to stm32-svd file structure (#5212)
|
||||
* **build/test**
|
||||
- build: use Golang 1.26 for all builds
|
||||
- build: actually use the version of llvm we are supposed to be testing by using brew link command
|
||||
- build: let scoop run updates to resolve binaryen install failures on Windows
|
||||
- ci: don't double zip release artifacts
|
||||
- test: increase default timeout from 1 to 2 minutes to prevent spurious CI fails
|
||||
- testdata: fix flaky timers test by draining ticker channel after Stop
|
||||
- testdata: more corpus entries (#5182)
|
||||
- add soypat/lneto to corpus
|
||||
- GNUmakefile: add context and expvar to stdlib tests
|
||||
- GNUmakefile: add encoding/xml to stdlib tests on Linux
|
||||
- main (test): skip mipsle test if the emulator is missing
|
||||
- make: remove machine without board from smoketest
|
||||
- stm32: add Arduino UNO Q to smoketests
|
||||
- flake: bump to nixpkgs 25.11
|
||||
- chore: update all github actions to latest versions
|
||||
- fix: use external 7zip for scoop installs on Windows
|
||||
|
||||
0.40.1
|
||||
---
|
||||
* **machine**
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||
FROM golang:1.25 AS tinygo-llvm
|
||||
FROM golang:1.26 AS tinygo-llvm
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y apt-utils make cmake clang-17 ninja-build && \
|
||||
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
|
||||
|
||||
# tinygo-compiler copies the compiler build over to a base Go container (without
|
||||
# all the build tools etc).
|
||||
FROM golang:1.25 AS tinygo-compiler
|
||||
FROM golang:1.26 AS tinygo-compiler
|
||||
|
||||
# Copy tinygo build.
|
||||
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
|
||||
|
||||
+71
-8
@@ -289,13 +289,13 @@ WASM_TOOLS_MODULE=go.bytecodealliance.org
|
||||
.PHONY: wasi-syscall
|
||||
wasi-syscall: wasi-cm
|
||||
rm -rf ./src/internal/wasi/*
|
||||
go run -modfile ./internal/wasm-tools/go.mod $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit
|
||||
go run $(WASM_TOOLS_MODULE)/cmd/wit-bindgen-go generate --versioned -o ./src/internal -p internal --cm internal/cm ./lib/wasi-cli/wit
|
||||
|
||||
# Copy package cm into src/internal/cm
|
||||
.PHONY: wasi-cm
|
||||
wasi-cm:
|
||||
rm -rf ./src/internal/cm/*
|
||||
rsync -rv --delete --exclude go.mod --exclude '*_test.go' --exclude '*_json.go' --exclude '*.md' --exclude LICENSE $(shell go list -modfile ./internal/wasm-tools/go.mod -m -f {{.Dir}} $(WASM_TOOLS_MODULE)/cm)/ ./src/internal/cm
|
||||
rsync -rv --delete --exclude go.mod --exclude '*_test.go' --exclude '*_json.go' --exclude '*.md' --exclude LICENSE $(shell go list -m -f {{.Dir}} $(WASM_TOOLS_MODULE)/cm)/ ./src/internal/cm
|
||||
|
||||
# Check for Node.js used during WASM tests.
|
||||
MIN_NODEJS_VERSION=18
|
||||
@@ -339,14 +339,17 @@ TEST_PACKAGES_FAST = \
|
||||
embed/internal/embedtest \
|
||||
encoding \
|
||||
encoding/ascii85 \
|
||||
errors \
|
||||
encoding/asn1 \
|
||||
encoding/base32 \
|
||||
encoding/base64 \
|
||||
encoding/csv \
|
||||
encoding/hex \
|
||||
expvar \
|
||||
go/ast \
|
||||
go/format \
|
||||
go/scanner \
|
||||
go/token \
|
||||
go/version \
|
||||
hash \
|
||||
hash/adler32 \
|
||||
@@ -359,6 +362,7 @@ TEST_PACKAGES_FAST = \
|
||||
math/cmplx \
|
||||
net/http/internal/ascii \
|
||||
net/mail \
|
||||
net/url \
|
||||
os \
|
||||
path \
|
||||
reflect \
|
||||
@@ -379,6 +383,7 @@ TEST_PACKAGES_FAST = \
|
||||
# crypto/des fails on wasi, needs panic()/recover()
|
||||
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic
|
||||
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows
|
||||
# encoding/xml takes a minute on linux and gives a stack overflow on wasi
|
||||
# image requires recover(), which is not yet supported on wasi
|
||||
# io/ioutil requires os.ReadDir, which is not yet supported on windows or wasi
|
||||
# mime: fail on wasi; neds panic()/recover()
|
||||
@@ -396,11 +401,13 @@ TEST_PACKAGES_FAST = \
|
||||
TEST_PACKAGES_LINUX := \
|
||||
archive/zip \
|
||||
compress/flate \
|
||||
context \
|
||||
crypto/aes \
|
||||
crypto/des \
|
||||
crypto/hmac \
|
||||
debug/dwarf \
|
||||
debug/plan9obj \
|
||||
encoding/xml \
|
||||
image \
|
||||
io/ioutil \
|
||||
mime \
|
||||
@@ -437,6 +444,7 @@ TEST_PACKAGES_NONWASM = \
|
||||
crypto/ecdsa \
|
||||
debug/macho \
|
||||
embed/internal/embedtest \
|
||||
expvar \
|
||||
go/format \
|
||||
os \
|
||||
testing \
|
||||
@@ -480,7 +488,7 @@ TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
|
||||
TEST_IOFS := false
|
||||
endif
|
||||
|
||||
TEST_SKIP_FLAG := -skip='TestExtraMethods|TestParseAndBytesRoundTrip/P256/Generic'
|
||||
TEST_SKIP_FLAG := -skip='TestExtraMethods|TestParseAndBytesRoundTrip/P256/Generic|TestAsValidation'
|
||||
TEST_ADDITIONAL_FLAGS ?=
|
||||
|
||||
# Test known-working standard library packages.
|
||||
@@ -626,7 +634,7 @@ smoketest: testchdir
|
||||
@$(MD5SUM) test.hex
|
||||
# test simulated boards on play.tinygo.org
|
||||
ifneq ($(WASM), 0)
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino_uno examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=hifive1b examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
@@ -644,6 +652,8 @@ ifneq ($(WASM), 0)
|
||||
@$(MD5SUM) test.wasm
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=pico examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=xiao_esp32s3 examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
endif
|
||||
# test all targets/boards
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
|
||||
@@ -814,6 +824,10 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=waveshare-rp2040-tiny examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=vicharak_shrike-lite examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=xiao-rp2350 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
# test pwm
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -873,18 +887,24 @@ ifneq ($(STM32), 0)
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=stm32l0x1 examples/serial
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/serial
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno-q examples/blinkm
|
||||
@$(MD5SUM) test.hex
|
||||
endif
|
||||
$(TINYGO) build -size short -o test.hex -target=atmega328pb examples/blinkm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/machinetest
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-leonardo examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino examples/pwm
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino -scheduler=tasks examples/blinky1
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-uno -scheduler=tasks examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-mega1280 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -896,13 +916,25 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark examples/mcp3008
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
ifneq ($(XTENSA), 0)
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32-generic examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-generic examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32s3-generic examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32-mini32 examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinkm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target m5stack-core2 examples/machinetest
|
||||
@@ -915,9 +947,39 @@ ifneq ($(XTENSA), 0)
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
# xiao-esp32s3
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/blinkm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/mcp3008
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/pwm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=xiao-esp32s3 examples/adc
|
||||
@$(MD5SUM) test.bin
|
||||
# esp32s3-supermini
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/blinkm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/mcp3008
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32s3-supermini examples/adc
|
||||
@$(MD5SUM) test.bin
|
||||
endif
|
||||
# esp32c3-supermini
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/blinkm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/mcp3008
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/pwm
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-supermini examples/adc
|
||||
@$(MD5SUM) test.bin
|
||||
|
||||
$(TINYGO) build -size short -o test.bin -target=esp-c3-32s-kit examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/machinetest
|
||||
@@ -930,6 +992,7 @@ endif
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
|
||||
$(TINYGO) build -size short -o test.bin -target=makerfabs-esp32c3spi35 examples/machinetest
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
|
||||
@@ -1123,7 +1186,7 @@ endif
|
||||
|
||||
.PHONY: tools
|
||||
tools:
|
||||
cd internal/tools && go generate -tags tools ./
|
||||
go generate -tags tools ./
|
||||
|
||||
LINTDIRS=src/os/ src/reflect/
|
||||
.PHONY: lint
|
||||
|
||||
@@ -6,6 +6,9 @@ TinyGo is a Go compiler intended for use in small places such as microcontroller
|
||||
|
||||
It reuses libraries used by the [Go language tools](https://golang.org/pkg/go/) alongside [LLVM](http://llvm.org) to provide an alternative way to compile programs written in the Go programming language.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> You can help TinyGo with a financial contribution using OpenCollective. Please see https://opencollective.com/tinygo for more information. Thank you!
|
||||
|
||||
## Embedded
|
||||
|
||||
Here is an example program that blinks the built-in LED when run directly on any supported board with onboard LED:
|
||||
@@ -31,10 +34,10 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
The above program can be compiled and run without modification on an Arduino Uno, an Adafruit ItsyBitsy M0, or any of the supported boards that have a built-in LED, just by setting the correct TinyGo compiler target. For example, this compiles and flashes an Arduino Uno:
|
||||
The above program can be compiled and run without modification on an [Arduino Uno](https://tinygo.org/docs/reference/microcontrollers/boards/arduino-uno), an [Adafruit Circuit Playground Express](https://tinygo.org/docs/reference/microcontrollers/featured/circuitplay-express), a [Seeed Studio XIAO-ESP32S3](https://tinygo.org/docs/reference/microcontrollers/featured/xiao-esp32s3) or any of the many supported boards that have a built-in LED, just by setting the correct TinyGo compiler target. For example, this compiles and flashes an Arduino Uno:
|
||||
|
||||
```shell
|
||||
tinygo flash -target arduino examples/blinky1
|
||||
tinygo flash -target arduino-uno examples/blinky1
|
||||
```
|
||||
|
||||
## WebAssembly
|
||||
@@ -63,7 +66,7 @@ tinygo build -buildmode=c-shared -o add.wasm -target=wasip1 add.go
|
||||
You can also use the same syntax as Go 1.24+:
|
||||
|
||||
```shell
|
||||
GOARCH=wasip1 GOOS=wasm tinygo build -buildmode=c-shared -o add.wasm add.go
|
||||
GOOS=wasip1 GOARCH=wasm tinygo build -buildmode=c-shared -o add.wasm add.go
|
||||
```
|
||||
|
||||
## Installation
|
||||
@@ -74,7 +77,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
|
||||
|
||||
### Embedded
|
||||
|
||||
You can compile TinyGo programs for over 94 different microcontroller boards.
|
||||
You can compile TinyGo programs for over 150 different microcontroller boards.
|
||||
|
||||
For more information, please see https://tinygo.org/docs/reference/microcontrollers/
|
||||
|
||||
@@ -139,7 +142,7 @@ Non-goals:
|
||||
|
||||
## Why this project exists
|
||||
|
||||
> We never expected Go to be an embedded language and so its got serious problems...
|
||||
> We never expected Go to be an embedded language, and so it’s got serious problems...
|
||||
|
||||
-- Rob Pike, [GopherCon 2014 Opening Keynote](https://www.youtube.com/watch?v=VoS7DsT1rdM&feature=youtu.be&t=2799)
|
||||
|
||||
|
||||
+26
-4
@@ -19,6 +19,7 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"slices"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -281,9 +282,13 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
allFiles[file.Name] = append(allFiles[file.Name], file)
|
||||
}
|
||||
}
|
||||
for name, files := range allFiles {
|
||||
name := name
|
||||
files := files
|
||||
// Sort embedded files by name to maintain output determinism.
|
||||
embedNames := make([]string, 0, len(allFiles))
|
||||
for _, files := range allFiles {
|
||||
embedNames = append(embedNames, files[0].Name)
|
||||
}
|
||||
slices.Sort(embedNames)
|
||||
for _, name := range embedNames {
|
||||
job := &compileJob{
|
||||
description: "make object file for " + name,
|
||||
run: func(job *compileJob) error {
|
||||
@@ -298,7 +303,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
sum := sha256.Sum256(data)
|
||||
hexSum := hex.EncodeToString(sum[:16])
|
||||
|
||||
for _, file := range files {
|
||||
for _, file := range allFiles[name] {
|
||||
file.Size = uint64(len(data))
|
||||
file.Hash = hexSum
|
||||
if file.NeedsData {
|
||||
@@ -541,6 +546,23 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to load bitcode file: %w", err)
|
||||
}
|
||||
// Resolve duplicate function definitions before linking.
|
||||
// This can happen when a newer Go version adds a function
|
||||
// body in a standard library package that was previously
|
||||
// just a declaration provided by //go:linkname from the
|
||||
// runtime. In that case, keep the existing (runtime)
|
||||
// definition by weakening the new one's linkage so the
|
||||
// LLVM linker discards it in favor of the existing one.
|
||||
for fn := pkgMod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
|
||||
if fn.IsDeclaration() {
|
||||
continue
|
||||
}
|
||||
existing := mod.NamedFunction(fn.Name())
|
||||
if existing.IsNil() || existing.IsDeclaration() {
|
||||
continue
|
||||
}
|
||||
fn.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
}
|
||||
err = llvm.LinkModules(mod, pkgMod)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to link module: %w", err)
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ struct AssemblerInvocation {
|
||||
EmitDwarfUnwindType EmitDwarfUnwind;
|
||||
|
||||
// Whether to emit compact-unwind for non-canonical entries.
|
||||
// Note: maybe overriden by other constraints.
|
||||
// Note: maybe overridden by other constraints.
|
||||
LLVM_PREFERRED_TYPE(bool)
|
||||
unsigned EmitCompactUnwindNonCanonical : 1;
|
||||
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
||||
|
||||
// Version range supported by TinyGo.
|
||||
const minorMin = 19
|
||||
const minorMax = 25
|
||||
const minorMax = 26
|
||||
|
||||
// Check that we support this Go toolchain version.
|
||||
gorootMajor, gorootMinor, err := goenv.GetGorootVersion()
|
||||
|
||||
+16
-2
@@ -167,9 +167,9 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
// double.
|
||||
args = append(args, "-mdouble=64")
|
||||
case "riscv32":
|
||||
args = append(args, "-march=rv32imac", "-fforce-enable-int128")
|
||||
args = append(args, "-march="+riscvMarch(config, "rv32imac"), "-fforce-enable-int128")
|
||||
case "riscv64":
|
||||
args = append(args, "-march=rv64gc")
|
||||
args = append(args, "-march="+riscvMarch(config, "rv64gc"))
|
||||
case "mips":
|
||||
args = append(args, "-fno-pic")
|
||||
}
|
||||
@@ -298,3 +298,17 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
once.Do(unlock)
|
||||
}, nil
|
||||
}
|
||||
|
||||
// riscvMarch returns the -march value for RISC-V library compilation.
|
||||
// It extracts the value from the target's cflags if present, otherwise
|
||||
// falls back to the provided default. This ensures libraries are compiled
|
||||
// with the correct ISA extensions for each target (e.g. rv32imc for
|
||||
// ESP32-C3 which lacks the atomic extension).
|
||||
func riscvMarch(config *compileopts.Config, defaultMarch string) string {
|
||||
for _, flag := range config.Target.CFlags {
|
||||
if strings.HasPrefix(flag, "-march=") {
|
||||
return flag[len("-march="):]
|
||||
}
|
||||
}
|
||||
return defaultMarch
|
||||
}
|
||||
|
||||
+5
-1
@@ -954,7 +954,11 @@ func findPackagePath(path string, packagePathMap map[string]string) (packagePath
|
||||
libPath := strings.TrimPrefix(path, filepath.Join(goenv.Get("TINYGOROOT"), "lib")+string(os.PathSeparator))
|
||||
parts := strings.SplitN(libPath, string(os.PathSeparator), 2)
|
||||
packagePath = "C " + parts[0]
|
||||
filename = parts[1]
|
||||
if len(parts) > 1 {
|
||||
filename = parts[1]
|
||||
} else {
|
||||
filename = parts[0]
|
||||
}
|
||||
} else if prefix := filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project", "compiler-rt"); strings.HasPrefix(path, prefix) {
|
||||
packagePath = "C compiler-rt"
|
||||
filename = strings.TrimPrefix(path, prefix+string(os.PathSeparator))
|
||||
|
||||
@@ -42,9 +42,9 @@ func TestBinarySize(t *testing.T) {
|
||||
// This is a small number of very diverse targets that we want to test.
|
||||
tests := []sizeTest{
|
||||
// microcontrollers
|
||||
{"hifive1b", "examples/echo", 3668, 280, 0, 2244},
|
||||
{"hifive1b", "examples/echo", 3680, 280, 0, 2252},
|
||||
{"microbit", "examples/serial", 2694, 342, 8, 2248},
|
||||
{"wioterminal", "examples/pininterrupt", 6837, 1491, 120, 6888},
|
||||
{"wioterminal", "examples/pininterrupt", 7074, 1510, 120, 7248},
|
||||
|
||||
// TODO: also check wasm. Right now this is difficult, because
|
||||
// wasm binaries are run through wasm-opt and therefore the
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
package cgo
|
||||
|
||||
/*
|
||||
#cgo linux CFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -I/usr/lib/llvm-19/include
|
||||
#cgo linux CFLAGS: -I/usr/include/llvm-19 -I/usr/include/llvm-c-19 -I/usr/lib/llvm-19/include -I/usr/lib64/llvm19/include
|
||||
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@19/include
|
||||
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@19/include
|
||||
#cgo freebsd CFLAGS: -I/usr/local/llvm19/include
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
package cgo
|
||||
|
||||
/*
|
||||
#cgo linux CFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -I/usr/lib/llvm-20/include
|
||||
#cgo linux CFLAGS: -I/usr/include/llvm-20 -I/usr/include/llvm-c-20 -I/usr/lib/llvm-20/include -I/usr/lib64/llvm20/include
|
||||
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@20/include
|
||||
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@20/include
|
||||
#cgo freebsd CFLAGS: -I/usr/local/llvm20/include
|
||||
|
||||
@@ -78,6 +78,7 @@ var validCompilerFlags = []*regexp.Regexp{
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-f(no-)?plt`),
|
||||
re(`-f(no-)?rtti`),
|
||||
re(`-f(no-)?short-enums`),
|
||||
re(`-f(no-)?split-stack`),
|
||||
re(`-f(no-)?stack-(.+)`),
|
||||
re(`-f(no-)?strict-aliasing`),
|
||||
|
||||
@@ -536,7 +536,7 @@ func (c *Config) Programmer() (method, openocdInterface string) {
|
||||
case "":
|
||||
// No configuration supplied.
|
||||
return c.Target.FlashMethod, c.Target.OpenOCDInterface
|
||||
case "openocd", "msd", "command":
|
||||
case "openocd", "msd", "command", "adb":
|
||||
// The -programmer flag only specifies the flash method.
|
||||
return c.Options.Programmer, c.Target.OpenOCDInterface
|
||||
case "bmp":
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
|
||||
type TargetSpec struct {
|
||||
Inherits []string `json:"inherits,omitempty"`
|
||||
InheritableOnly bool `json:"inheritable-only"` // this target is only meant to be inherited from, not used directly
|
||||
Triple string `json:"llvm-target,omitempty"`
|
||||
CPU string `json:"cpu,omitempty"`
|
||||
ABI string `json:"target-abi,omitempty"` // roughly equivalent to -mabi= flag
|
||||
@@ -63,6 +64,9 @@ type TargetSpec struct {
|
||||
OpenOCDCommands []string `json:"openocd-commands,omitempty"`
|
||||
OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd
|
||||
JLinkDevice string `json:"jlink-device,omitempty"`
|
||||
ADBPreCommands []string `json:"adb-pre-commands,omitempty"`
|
||||
ADBPushRemote string `json:"adb-push-remote,omitempty"`
|
||||
ADBPostCommands []string `json:"adb-post-commands,omitempty"`
|
||||
CodeModel string `json:"code-model,omitempty"`
|
||||
RelocationModel string `json:"relocation-model,omitempty"`
|
||||
WITPackage string `json:"wit-package,omitempty"`
|
||||
@@ -148,6 +152,11 @@ func (spec *TargetSpec) loadFromGivenStr(str string) error {
|
||||
|
||||
// resolveInherits loads inherited targets, recursively.
|
||||
func (spec *TargetSpec) resolveInherits() error {
|
||||
// Save InheritableOnly before resolving, since it must not propagate
|
||||
// from parent to child (a board target should not become inheritable-only
|
||||
// just because its parent processor target is).
|
||||
inheritableOnly := spec.InheritableOnly
|
||||
|
||||
// First create a new spec with all the inherited properties.
|
||||
newSpec := &TargetSpec{}
|
||||
for _, name := range spec.Inherits {
|
||||
@@ -173,6 +182,9 @@ func (spec *TargetSpec) resolveInherits() error {
|
||||
}
|
||||
*spec = *newSpec
|
||||
|
||||
// Restore InheritableOnly from the original spec, not from parents.
|
||||
spec.InheritableOnly = inheritableOnly
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -239,10 +251,17 @@ func GetTargetSpecs() (map[string]*TargetSpec, error) {
|
||||
continue
|
||||
}
|
||||
path := filepath.Join(dir, entry.Name())
|
||||
|
||||
spec, err := LoadTarget(&Options{Target: path})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not list target: %w", err)
|
||||
}
|
||||
|
||||
if spec.InheritableOnly {
|
||||
// Skip targets that are only meant to be inherited from, not used directly.
|
||||
continue
|
||||
}
|
||||
|
||||
if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" {
|
||||
// This doesn't look like a regular target file, but rather like
|
||||
// a parent target (such as targets/cortex-m.json).
|
||||
|
||||
@@ -23,6 +23,37 @@ func TestLoadTarget(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTargetSpecs_InheritableOnlyTargetsExcluded(t *testing.T) {
|
||||
specs, err := GetTargetSpecs()
|
||||
if err != nil {
|
||||
t.Fatal("GetTargetSpecs failed:", err)
|
||||
}
|
||||
|
||||
// Inheritable-only processor-level targets should not appear in the listing.
|
||||
inheritableOnlyTargets := []string{"esp32", "esp32c3", "esp32s3", "esp8266", "rp2040", "rp2350", "rp2350b"}
|
||||
for _, name := range inheritableOnlyTargets {
|
||||
if _, ok := specs[name]; ok {
|
||||
t.Errorf("inheritable-only target %q should not appear in GetTargetSpecs", name)
|
||||
}
|
||||
}
|
||||
|
||||
// Board targets that inherit from inheritable-only targets should still appear.
|
||||
boardTargets := []string{"esp32-coreboard-v2", "pico"}
|
||||
for _, name := range boardTargets {
|
||||
if _, ok := specs[name]; !ok {
|
||||
t.Errorf("board target %q should appear in GetTargetSpecs", name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadTarget_InheritableOnlyTargetStillLoadable(t *testing.T) {
|
||||
// Inheritable-only targets should still be loadable directly (for building).
|
||||
_, err := LoadTarget(&Options{Target: "esp32"})
|
||||
if err != nil {
|
||||
t.Errorf("LoadTarget should still load inheritable-only target esp32: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverrideProperties(t *testing.T) {
|
||||
baseAutoStackSize := true
|
||||
base := &TargetSpec{
|
||||
|
||||
@@ -873,6 +873,10 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
||||
// with a LLVM intrinsic.
|
||||
continue
|
||||
}
|
||||
if ok := b.defineCryptoIntrinsic(); ok {
|
||||
// Body of this function was replaced
|
||||
continue
|
||||
}
|
||||
if member.Blocks == nil {
|
||||
// Try to define this as an intrinsic function.
|
||||
b.defineIntrinsicFunction()
|
||||
@@ -1976,10 +1980,14 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
return b.emitSV64Call(instr.Args, getPos(instr))
|
||||
case strings.HasPrefix(name, "(device/riscv.CSR)."):
|
||||
return b.emitCSROperation(instr)
|
||||
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall"):
|
||||
case (strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.Syscall") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscall")) && name != "syscall.SyscallN":
|
||||
if b.GOOS != "darwin" {
|
||||
return b.createSyscall(instr)
|
||||
}
|
||||
case name == "syscall.syscalln":
|
||||
if b.GOOS == "windows" {
|
||||
return b.createSyscalln(instr)
|
||||
}
|
||||
case strings.HasPrefix(name, "syscall.rawSyscallNoError") || strings.HasPrefix(name, "golang.org/x/sys/unix.RawSyscallNoError"):
|
||||
return b.createRawSyscallNoError(instr)
|
||||
case name == "runtime.supportsRecover":
|
||||
|
||||
@@ -99,6 +99,9 @@ func typeHasPointers(t llvm.Type) bool {
|
||||
}
|
||||
return false
|
||||
case llvm.ArrayTypeKind:
|
||||
if t.ArrayLength() == 0 {
|
||||
return false
|
||||
}
|
||||
if typeHasPointers(t.ElementType()) {
|
||||
return true
|
||||
}
|
||||
|
||||
+153
-37
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -17,6 +18,12 @@ import (
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// numMethodHasMethodSet is a flag in bit 15 of the numMethod field (uint16) in
|
||||
// Named, Pointer, and Struct type descriptors. When set, an inline method set
|
||||
// is present in the type descriptor. Must match the constant in
|
||||
// src/internal/reflectlite/type.go.
|
||||
const numMethodHasMethodSet = 0x8000
|
||||
|
||||
// Type kinds for basic types.
|
||||
// They must match the constants for the Kind type in src/reflect/type.go.
|
||||
var basicTypes = [...]uint8{
|
||||
@@ -183,6 +190,16 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
typeFieldTypes := []*types.Var{
|
||||
types.NewVar(token.NoPos, nil, "kind", types.Typ[types.Int8]),
|
||||
}
|
||||
// Compute the method set value for types that support methods.
|
||||
var methods []*types.Func
|
||||
for i := 0; i < ms.Len(); i++ {
|
||||
methods = append(methods, ms.At(i).Obj().(*types.Func))
|
||||
}
|
||||
methodSetType := types.NewStruct([]*types.Var{
|
||||
types.NewVar(token.NoPos, nil, "length", types.Typ[types.Uintptr]),
|
||||
types.NewVar(token.NoPos, nil, "methods", types.NewArray(types.Typ[types.UnsafePointer], int64(len(methods)))),
|
||||
}, nil)
|
||||
methodSetValue := c.getMethodSetValue(methods)
|
||||
switch typ := typ.(type) {
|
||||
case *types.Basic:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
@@ -199,6 +216,13 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "underlying", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]),
|
||||
)
|
||||
if len(methods) > 0 {
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
)
|
||||
}
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "name", types.NewArray(types.Typ[types.Int8], int64(len(pkgname)+1+len(name)+1))),
|
||||
)
|
||||
case *types.Chan:
|
||||
@@ -218,6 +242,11 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "elementType", types.Typ[types.UnsafePointer]),
|
||||
)
|
||||
if len(methods) > 0 {
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
)
|
||||
}
|
||||
case *types.Array:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
@@ -242,11 +271,16 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
|
||||
)
|
||||
if len(methods) > 0 {
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
)
|
||||
}
|
||||
case *types.Interface:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "methods", methodSetType),
|
||||
)
|
||||
// TODO: methods
|
||||
case *types.Signature:
|
||||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
@@ -292,14 +326,24 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
pkgname = pkg.Name()
|
||||
}
|
||||
pkgPathPtr := c.pkgPathPtr(pkgpath)
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Underlying()), // underlying
|
||||
pkgPathPtr, // pkgpath pointer
|
||||
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
|
||||
namedNumMethods := uint64(numMethods)
|
||||
if namedNumMethods&numMethodHasMethodSet != 0 {
|
||||
panic("numMethods overflow: too many exported methods on named type " + name)
|
||||
}
|
||||
metabyte |= 1 << 5 // "named" flag
|
||||
if len(methods) > 0 {
|
||||
namedNumMethods |= numMethodHasMethodSet
|
||||
}
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), namedNumMethods, false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Underlying()), // underlying
|
||||
pkgPathPtr, // pkgpath pointer
|
||||
}
|
||||
if len(methods) > 0 {
|
||||
typeFields = append(typeFields, methodSetValue) // methods
|
||||
}
|
||||
typeFields = append(typeFields, c.ctx.ConstString(pkgname+"."+name+"\x00", false)) // name
|
||||
metabyte |= 1 << 5 // "named" flag
|
||||
case *types.Chan:
|
||||
var dir reflectChanDir
|
||||
switch typ.Dir() {
|
||||
@@ -323,10 +367,20 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
c.getTypeCode(typ.Elem()), // elementType
|
||||
}
|
||||
case *types.Pointer:
|
||||
ptrNumMethods := uint64(numMethods)
|
||||
if ptrNumMethods&numMethodHasMethodSet != 0 {
|
||||
panic("numMethods overflow: too many exported methods on pointer type")
|
||||
}
|
||||
if len(methods) > 0 {
|
||||
ptrNumMethods |= numMethodHasMethodSet
|
||||
}
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||
llvm.ConstInt(c.ctx.Int16Type(), ptrNumMethods, false), // numMethods
|
||||
c.getTypeCode(typ.Elem()),
|
||||
}
|
||||
if len(methods) > 0 {
|
||||
typeFields = append(typeFields, methodSetValue)
|
||||
}
|
||||
case *types.Array:
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), 0, false), // numMethods
|
||||
@@ -353,9 +407,16 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
|
||||
llvmStructType := c.getLLVMType(typ)
|
||||
size := c.targetData.TypeStoreSize(llvmStructType)
|
||||
structNumMethods := uint64(numMethods)
|
||||
if structNumMethods&numMethodHasMethodSet != 0 {
|
||||
panic("numMethods overflow: too many exported methods on struct type")
|
||||
}
|
||||
if len(methods) > 0 {
|
||||
structNumMethods |= numMethodHasMethodSet
|
||||
}
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
llvm.ConstInt(c.ctx.Int16Type(), structNumMethods, false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
pkgPathPtr,
|
||||
llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
|
||||
@@ -407,9 +468,14 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
}))
|
||||
}
|
||||
typeFields = append(typeFields, llvm.ConstArray(structFieldType, fields))
|
||||
if len(methods) > 0 {
|
||||
typeFields = append(typeFields, methodSetValue)
|
||||
}
|
||||
case *types.Interface:
|
||||
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
|
||||
// TODO: methods
|
||||
typeFields = []llvm.Value{
|
||||
c.getTypeCode(types.NewPointer(typ)),
|
||||
methodSetValue,
|
||||
}
|
||||
case *types.Signature:
|
||||
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
|
||||
// TODO: params, return values, etc
|
||||
@@ -696,17 +762,11 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
||||
// This type assertion always succeeds, so we can just set commaOk to true.
|
||||
commaOk = llvm.ConstInt(b.ctx.Int1Type(), 1, true)
|
||||
} else {
|
||||
// Type assert on interface type with methods.
|
||||
// This is a call to an interface type assert function.
|
||||
// The interface lowering pass will define this function by filling it
|
||||
// with a type switch over all concrete types that implement this
|
||||
// interface, and returning whether it's one of the matched types.
|
||||
// This is very different from how interface asserts are implemented in
|
||||
// the main Go compiler, where the runtime checks whether the type
|
||||
// implements each method of the interface. See:
|
||||
// https://research.swtch.com/interfaces
|
||||
fn := b.getInterfaceImplementsFunc(expr.AssertedType)
|
||||
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
|
||||
// Type assert on an interface type with methods.
|
||||
// Create a call to a declared-but-not-defined function that will
|
||||
// be lowered by the interface lowering pass into a type-ID
|
||||
// comparison chain.
|
||||
commaOk = b.createInterfaceTypeAssert(intf, actualTypeNum)
|
||||
}
|
||||
} else {
|
||||
name, _ := getTypeCodeName(expr.AssertedType)
|
||||
@@ -783,20 +843,58 @@ func (c *compilerContext) getMethodsString(itf *types.Interface) string {
|
||||
return strings.Join(methods, "; ")
|
||||
}
|
||||
|
||||
// getInterfaceImplementsFunc returns a declared function that works as a type
|
||||
// switch. The interface lowering pass will define this function.
|
||||
func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) llvm.Value {
|
||||
s, _ := getTypeCodeName(assertedType.Underlying())
|
||||
fnName := s + ".$typeassert"
|
||||
llvmFn := c.mod.NamedFunction(fnName)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFnType := llvm.FunctionType(c.ctx.Int1Type(), []llvm.Type{c.dataPtrType}, false)
|
||||
llvmFn = llvm.AddFunction(c.mod, fnName, llvmFnType)
|
||||
c.addStandardDeclaredAttributes(llvmFn)
|
||||
methods := c.getMethodsString(assertedType.Underlying().(*types.Interface))
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("tinygo-methods", methods))
|
||||
// getMethodSetValue creates the method set struct value for a list of methods.
|
||||
// The struct contains a length and a sorted array of method signature pointers.
|
||||
func (c *compilerContext) getMethodSetValue(methods []*types.Func) llvm.Value {
|
||||
// Create a sorted list of method signature global names.
|
||||
type methodRef struct {
|
||||
name string
|
||||
value llvm.Value
|
||||
}
|
||||
return llvmFn
|
||||
var refs []methodRef
|
||||
for _, method := range methods {
|
||||
name := method.Name()
|
||||
if !token.IsExported(name) {
|
||||
name = method.Pkg().Path() + "." + name
|
||||
}
|
||||
s, _ := getTypeCodeName(method.Type())
|
||||
globalName := "reflect/types.signature:" + name + ":" + s
|
||||
value := c.mod.NamedGlobal(globalName)
|
||||
if value.IsNil() {
|
||||
value = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), globalName)
|
||||
value.SetInitializer(llvm.ConstNull(c.ctx.Int8Type()))
|
||||
value.SetGlobalConstant(true)
|
||||
value.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
value.SetAlignment(1)
|
||||
if c.Debug {
|
||||
file := c.getDIFile("<Go type>")
|
||||
diglobal := c.dibuilder.CreateGlobalVariableExpression(file, llvm.DIGlobalVariableExpression{
|
||||
Name: globalName,
|
||||
File: file,
|
||||
Line: 1,
|
||||
Type: c.getDIType(types.Typ[types.Uint8]),
|
||||
LocalToUnit: false,
|
||||
Expr: c.dibuilder.CreateExpression(nil),
|
||||
AlignInBits: 8,
|
||||
})
|
||||
value.AddMetadata(0, diglobal)
|
||||
}
|
||||
}
|
||||
refs = append(refs, methodRef{globalName, value})
|
||||
}
|
||||
sort.Slice(refs, func(i, j int) bool {
|
||||
return refs[i].name < refs[j].name
|
||||
})
|
||||
|
||||
var values []llvm.Value
|
||||
for _, ref := range refs {
|
||||
values = append(values, ref.value)
|
||||
}
|
||||
|
||||
return c.ctx.ConstStruct([]llvm.Value{
|
||||
llvm.ConstInt(c.uintptrType, uint64(len(values)), false),
|
||||
llvm.ConstArray(c.dataPtrType, values),
|
||||
}, false)
|
||||
}
|
||||
|
||||
// getInvokeFunction returns the thunk to call the given interface method. The
|
||||
@@ -823,6 +921,24 @@ func (c *compilerContext) getInvokeFunction(instr *ssa.CallCommon) llvm.Value {
|
||||
return llvmFn
|
||||
}
|
||||
|
||||
// createInterfaceTypeAssert creates a call to a declared-but-not-defined
|
||||
// $typeassert function for the given interface. This function will be defined
|
||||
// by the interface lowering pass as a type-ID comparison chain, avoiding the
|
||||
// need for runtime.typeImplementsMethodSet at compile time.
|
||||
func (b *builder) createInterfaceTypeAssert(intf *types.Interface, actualType llvm.Value) llvm.Value {
|
||||
s, _ := getTypeCodeName(intf)
|
||||
fnName := s + ".$typeassert"
|
||||
llvmFn := b.mod.NamedFunction(fnName)
|
||||
if llvmFn.IsNil() {
|
||||
llvmFnType := llvm.FunctionType(b.ctx.Int1Type(), []llvm.Type{b.dataPtrType}, false)
|
||||
llvmFn = llvm.AddFunction(b.mod, fnName, llvmFnType)
|
||||
b.addStandardDeclaredAttributes(llvmFn)
|
||||
methods := b.getMethodsString(intf)
|
||||
llvmFn.AddFunctionAttr(b.ctx.CreateStringAttribute("tinygo-methods", methods))
|
||||
}
|
||||
return b.CreateCall(llvmFn.GlobalValueType(), llvmFn, []llvm.Value{actualType}, "")
|
||||
}
|
||||
|
||||
// getInterfaceInvokeWrapper returns a wrapper for the given method so it can be
|
||||
// invoked from an interface. The wrapper takes in a pointer to the underlying
|
||||
// value, dereferences or unpacks it if necessary, and calls the real method.
|
||||
|
||||
@@ -208,6 +208,23 @@ func (b *builder) defineMathOp() {
|
||||
b.CreateRet(result)
|
||||
}
|
||||
|
||||
func (b *builder) defineCryptoIntrinsic() bool {
|
||||
if b.fn.Pkg.Pkg.Path() != "crypto/internal/constanttime" {
|
||||
return false
|
||||
}
|
||||
|
||||
switch b.fn.Name() {
|
||||
case "boolToUint8":
|
||||
b.createFunctionStart(true)
|
||||
param := b.getValue(b.fn.Params[0], b.fn.Pos())
|
||||
result := b.CreateZExt(param, b.ctx.Int8Type(), "")
|
||||
b.CreateRet(result)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Implement most math/bits functions.
|
||||
//
|
||||
// This implements all the functions that operate on bits. It does not yet
|
||||
|
||||
+90
-90
@@ -1,10 +1,10 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
@@ -231,6 +231,12 @@ func (c *compilerContext) makeGlobalArray(buf []byte, name string, elementType l
|
||||
//
|
||||
// For details on what's in this value, see src/runtime/gc_precise.go.
|
||||
func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Value {
|
||||
if !typeHasPointers(t) {
|
||||
// There are no pointers in this type, so we can simplify the layout.
|
||||
layout := (uint64(1) << 1) | 1
|
||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||
}
|
||||
|
||||
// Use the element type for arrays. This works even for nested arrays.
|
||||
for {
|
||||
kind := t.TypeKind()
|
||||
@@ -248,54 +254,29 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
||||
break
|
||||
}
|
||||
|
||||
// Do a few checks to see whether we need to generate any object layout
|
||||
// information at all.
|
||||
// Create the pointer bitmap.
|
||||
objectSizeBytes := c.targetData.TypeAllocSize(t)
|
||||
pointerAlignment := uint64(c.targetData.PrefTypeAlignment(c.dataPtrType))
|
||||
bitmapLen := objectSizeBytes / pointerAlignment
|
||||
bitmapBytes := (bitmapLen + 7) / 8
|
||||
bitmap := make([]byte, bitmapBytes, max(bitmapBytes, 8))
|
||||
c.buildPointerBitmap(bitmap, pointerAlignment, pos, t, 0)
|
||||
|
||||
// Try to encode the layout inline.
|
||||
pointerSize := c.targetData.TypeAllocSize(c.dataPtrType)
|
||||
pointerAlignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
|
||||
if objectSizeBytes < pointerSize {
|
||||
// Too small to contain a pointer.
|
||||
layout := (uint64(1) << 1) | 1
|
||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||
}
|
||||
bitmap := c.getPointerBitmap(t, pos)
|
||||
if bitmap.BitLen() == 0 {
|
||||
// There are no pointers in this type, so we can simplify the layout.
|
||||
// TODO: this can be done in many other cases, e.g. when allocating an
|
||||
// array (like [4][]byte, which repeats a slice 4 times).
|
||||
layout := (uint64(1) << 1) | 1
|
||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||
}
|
||||
if objectSizeBytes%uint64(pointerAlignment) != 0 {
|
||||
// This shouldn't happen except for packed structs, which aren't
|
||||
// currently used.
|
||||
c.addError(pos, "internal error: unexpected object size for object with pointer field")
|
||||
return llvm.ConstNull(c.dataPtrType)
|
||||
}
|
||||
objectSizeWords := objectSizeBytes / uint64(pointerAlignment)
|
||||
|
||||
pointerBits := pointerSize * 8
|
||||
var sizeFieldBits uint64
|
||||
switch pointerBits {
|
||||
case 16:
|
||||
sizeFieldBits = 4
|
||||
case 32:
|
||||
sizeFieldBits = 5
|
||||
case 64:
|
||||
sizeFieldBits = 6
|
||||
default:
|
||||
panic("unknown pointer size")
|
||||
}
|
||||
layoutFieldBits := pointerBits - 1 - sizeFieldBits
|
||||
if bitmapLen < pointerBits {
|
||||
rawMask := binary.LittleEndian.Uint64(bitmap[0:8])
|
||||
layout := rawMask*pointerBits + bitmapLen
|
||||
layout <<= 1
|
||||
layout |= 1
|
||||
|
||||
// Try to emit the value as an inline integer. This is possible in most
|
||||
// cases.
|
||||
if objectSizeWords < layoutFieldBits {
|
||||
// If it can be stored directly in the pointer value, do so.
|
||||
// The runtime knows that if the least significant bit of the pointer is
|
||||
// set, the pointer contains the value itself.
|
||||
layout := bitmap.Uint64()<<(sizeFieldBits+1) | (objectSizeWords << 1) | 1
|
||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||
// Check if the layout fits.
|
||||
layout &= 1<<pointerBits - 1
|
||||
if (layout>>1)/pointerBits == rawMask {
|
||||
// No set bits were shifted off.
|
||||
return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, layout, false), c.dataPtrType)
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately, the object layout is too big to fit in a pointer-sized
|
||||
@@ -303,25 +284,24 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
||||
|
||||
// Try first whether the global already exists. All objects with a
|
||||
// particular name have the same type, so this is possible.
|
||||
globalName := "runtime/gc.layout:" + fmt.Sprintf("%d-%0*x", objectSizeWords, (objectSizeWords+15)/16, bitmap)
|
||||
globalName := "runtime/gc.layout:" + fmt.Sprintf("%d-%0*x", bitmapLen, (bitmapLen+15)/16, bitmap)
|
||||
global := c.mod.NamedGlobal(globalName)
|
||||
if !global.IsNil() {
|
||||
return global
|
||||
}
|
||||
|
||||
// Create the global initializer.
|
||||
bitmapBytes := make([]byte, int(objectSizeWords+7)/8)
|
||||
bitmap.FillBytes(bitmapBytes)
|
||||
reverseBytes(bitmapBytes) // big-endian to little-endian
|
||||
var bitmapByteValues []llvm.Value
|
||||
for _, b := range bitmapBytes {
|
||||
bitmapByteValues = append(bitmapByteValues, llvm.ConstInt(c.ctx.Int8Type(), uint64(b), false))
|
||||
bitmapByteValues := make([]llvm.Value, bitmapBytes)
|
||||
i8 := c.ctx.Int8Type()
|
||||
for i, b := range bitmap {
|
||||
bitmapByteValues[i] = llvm.ConstInt(i8, uint64(b), false)
|
||||
}
|
||||
initializer := c.ctx.ConstStruct([]llvm.Value{
|
||||
llvm.ConstInt(c.uintptrType, objectSizeWords, false),
|
||||
llvm.ConstArray(c.ctx.Int8Type(), bitmapByteValues),
|
||||
llvm.ConstInt(c.uintptrType, bitmapLen, false),
|
||||
llvm.ConstArray(i8, bitmapByteValues),
|
||||
}, false)
|
||||
|
||||
// Create the actual global.
|
||||
global = llvm.AddGlobal(c.mod, initializer.Type(), globalName)
|
||||
global.SetInitializer(initializer)
|
||||
global.SetUnnamedAddr(true)
|
||||
@@ -329,6 +309,7 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
||||
global.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
if c.targetData.PrefTypeAlignment(c.uintptrType) < 2 {
|
||||
// AVR doesn't have alignment by default.
|
||||
// The lowest bit must be unset to distinguish this from an inline layout.
|
||||
global.SetAlignment(2)
|
||||
}
|
||||
if c.Debug && pos != token.NoPos {
|
||||
@@ -360,52 +341,71 @@ func (c *compilerContext) createObjectLayout(t llvm.Type, pos token.Pos) llvm.Va
|
||||
return global
|
||||
}
|
||||
|
||||
// getPointerBitmap scans the given LLVM type for pointers and sets bits in a
|
||||
// bigint at the word offset that contains a pointer. This scan is recursive.
|
||||
func (c *compilerContext) getPointerBitmap(typ llvm.Type, pos token.Pos) *big.Int {
|
||||
alignment := c.targetData.PrefTypeAlignment(c.dataPtrType)
|
||||
switch typ.TypeKind() {
|
||||
// buildPointerBitmap scans the given LLVM type for pointers and sets bits in a
|
||||
// bitmap at the word offset that contains a pointer. This scan is recursive.
|
||||
func (c *compilerContext) buildPointerBitmap(
|
||||
dst []byte,
|
||||
ptrAlign uint64,
|
||||
pos token.Pos,
|
||||
t llvm.Type,
|
||||
offset uint64,
|
||||
) {
|
||||
switch t.TypeKind() {
|
||||
case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
|
||||
return big.NewInt(0)
|
||||
// These types do not contain pointers.
|
||||
|
||||
case llvm.PointerTypeKind:
|
||||
return big.NewInt(1)
|
||||
// Set the corresponding position in the bitmap.
|
||||
dst[offset/8] |= 1 << (offset % 8)
|
||||
|
||||
case llvm.StructTypeKind:
|
||||
ptrs := big.NewInt(0)
|
||||
for i, subtyp := range typ.StructElementTypes() {
|
||||
subptrs := c.getPointerBitmap(subtyp, pos)
|
||||
if subptrs.BitLen() == 0 {
|
||||
// Recurse over struct elements.
|
||||
for i, et := range t.StructElementTypes() {
|
||||
eo := c.targetData.ElementOffset(t, i)
|
||||
if eo%uint64(ptrAlign) != 0 {
|
||||
if typeHasPointers(et) {
|
||||
// This error will let the compilation fail, but by continuing
|
||||
// the error can still easily be shown.
|
||||
c.addError(pos, "internal error: allocated struct contains unaligned pointer")
|
||||
}
|
||||
continue
|
||||
}
|
||||
offset := c.targetData.ElementOffset(typ, i)
|
||||
if offset%uint64(alignment) != 0 {
|
||||
// This error will let the compilation fail, but by continuing
|
||||
// the error can still easily be shown.
|
||||
c.addError(pos, "internal error: allocated struct contains unaligned pointer")
|
||||
continue
|
||||
}
|
||||
subptrs.Lsh(subptrs, uint(offset)/uint(alignment))
|
||||
ptrs.Or(ptrs, subptrs)
|
||||
c.buildPointerBitmap(
|
||||
dst,
|
||||
ptrAlign,
|
||||
pos,
|
||||
et,
|
||||
offset+(eo/ptrAlign),
|
||||
)
|
||||
}
|
||||
return ptrs
|
||||
|
||||
case llvm.ArrayTypeKind:
|
||||
subtyp := typ.ElementType()
|
||||
subptrs := c.getPointerBitmap(subtyp, pos)
|
||||
ptrs := big.NewInt(0)
|
||||
if subptrs.BitLen() == 0 {
|
||||
return ptrs
|
||||
// Recurse over array elements.
|
||||
len := t.ArrayLength()
|
||||
if len <= 0 {
|
||||
return
|
||||
}
|
||||
elementSize := c.targetData.TypeAllocSize(subtyp)
|
||||
if elementSize%uint64(alignment) != 0 {
|
||||
// This error will let the compilation fail (but continues so that
|
||||
// other errors can be shown).
|
||||
c.addError(pos, "internal error: allocated array contains unaligned pointer")
|
||||
return ptrs
|
||||
et := t.ElementType()
|
||||
elementSize := c.targetData.TypeAllocSize(et)
|
||||
if elementSize%ptrAlign != 0 {
|
||||
if typeHasPointers(et) {
|
||||
// This error will let the compilation fail (but continues so that
|
||||
// other errors can be shown).
|
||||
c.addError(pos, "internal error: allocated array contains unaligned pointer")
|
||||
}
|
||||
return
|
||||
}
|
||||
for i := 0; i < typ.ArrayLength(); i++ {
|
||||
ptrs.Lsh(ptrs, uint(elementSize)/uint(alignment))
|
||||
ptrs.Or(ptrs, subptrs)
|
||||
elementSize /= ptrAlign
|
||||
for i := 0; i < len; i++ {
|
||||
c.buildPointerBitmap(
|
||||
dst,
|
||||
ptrAlign,
|
||||
pos,
|
||||
et,
|
||||
offset+uint64(i)*elementSize,
|
||||
)
|
||||
}
|
||||
return ptrs
|
||||
|
||||
default:
|
||||
// Should not happen.
|
||||
panic("unknown LLVM type")
|
||||
|
||||
+1
-1
@@ -540,7 +540,7 @@ func (c *compilerContext) isValidWasmType(typ types.Type, site wasmSite) bool {
|
||||
}
|
||||
for i := 0; i < typ.NumFields(); i++ {
|
||||
ftyp := typ.Field(i).Type()
|
||||
if ftyp.String() == "structs.HostLayout" {
|
||||
if types.Unalias(ftyp).String() == "structs.HostLayout" {
|
||||
hasHostLayout = true
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -349,6 +349,130 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// createSyscalln emits instructions for the syscall.syscalln function on
|
||||
// Windows. This handles the variadic calling convention used in Go 1.26+:
|
||||
//
|
||||
// func syscalln(fn, n uintptr, args ...uintptr) (r1, r2 uintptr, err Errno)
|
||||
//
|
||||
// The function generates a switch on n to dispatch to the correct fixed-argument
|
||||
// function pointer call with SetLastError(0)/GetLastError() wrapping.
|
||||
func (b *builder) createSyscalln(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
const maxArgs = 18 // Windows syscalls support up to 18 args
|
||||
|
||||
isI386 := strings.HasPrefix(b.Triple, "i386-")
|
||||
|
||||
// Get the function pointer (call.Args[0]) and n (call.Args[1]).
|
||||
fn := b.getValue(call.Args[0], getPos(call))
|
||||
fnPtr := b.CreateIntToPtr(fn, b.dataPtrType, "")
|
||||
n := b.getValue(call.Args[1], getPos(call))
|
||||
|
||||
// Get the variadic args slice (call.Args[2]).
|
||||
// In SSA, the variadic slice is the third argument.
|
||||
var argsPtr llvm.Value
|
||||
if len(call.Args) > 2 {
|
||||
argsSlice := b.getValue(call.Args[2], getPos(call))
|
||||
argsPtr = b.CreateExtractValue(argsSlice, 0, "args.data")
|
||||
} else {
|
||||
argsPtr = llvm.ConstNull(b.dataPtrType)
|
||||
}
|
||||
|
||||
// Prepare SetLastError and GetLastError.
|
||||
setLastError := b.mod.NamedFunction("SetLastError")
|
||||
if setLastError.IsNil() {
|
||||
llvmType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.ctx.Int32Type()}, false)
|
||||
setLastError = llvm.AddFunction(b.mod, "SetLastError", llvmType)
|
||||
if isI386 {
|
||||
setLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
|
||||
}
|
||||
}
|
||||
getLastError := b.mod.NamedFunction("GetLastError")
|
||||
if getLastError.IsNil() {
|
||||
llvmType := llvm.FunctionType(b.ctx.Int32Type(), nil, false)
|
||||
getLastError = llvm.AddFunction(b.mod, "GetLastError", llvmType)
|
||||
if isI386 {
|
||||
getLastError.SetFunctionCallConv(llvm.X86StdcallCallConv)
|
||||
}
|
||||
}
|
||||
|
||||
retType := b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType, b.uintptrType}, false)
|
||||
|
||||
// Create the merge block where all cases converge.
|
||||
mergeBB := b.insertBasicBlock("syscalln.merge")
|
||||
|
||||
// Create the default (panic) block.
|
||||
panicBB := b.insertBasicBlock("syscalln.panic")
|
||||
|
||||
// Create the switch on n.
|
||||
sw := b.CreateSwitch(n, panicBB, maxArgs+1)
|
||||
|
||||
// We'll collect blocks and values for the PHI node.
|
||||
var incomingVals []llvm.Value
|
||||
var incomingBlocks []llvm.BasicBlock
|
||||
|
||||
// Generate a case for each arg count 0..maxArgs.
|
||||
for i := 0; i <= maxArgs; i++ {
|
||||
caseBB := b.insertBasicBlock("syscalln.case" + strconv.Itoa(i))
|
||||
sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), caseBB)
|
||||
b.SetInsertPointAtEnd(caseBB)
|
||||
|
||||
// Load args[0] through args[i-1] from the slice data pointer.
|
||||
var params []llvm.Value
|
||||
var paramTypes []llvm.Type
|
||||
for j := 0; j < i; j++ {
|
||||
gep := b.CreateInBoundsGEP(b.uintptrType, argsPtr, []llvm.Value{
|
||||
llvm.ConstInt(b.ctx.Int32Type(), uint64(j), false),
|
||||
}, "")
|
||||
arg := b.CreateLoad(b.uintptrType, gep, "")
|
||||
params = append(params, arg)
|
||||
paramTypes = append(paramTypes, b.uintptrType)
|
||||
}
|
||||
|
||||
// SetLastError(0)
|
||||
setCall := b.CreateCall(setLastError.GlobalValueType(), setLastError, []llvm.Value{llvm.ConstNull(b.ctx.Int32Type())}, "")
|
||||
var sp llvm.Value
|
||||
if isI386 {
|
||||
setCall.SetInstructionCallConv(llvm.X86StdcallCallConv)
|
||||
sp = b.readStackPointer()
|
||||
}
|
||||
|
||||
// Call fn(args...)
|
||||
fnType := llvm.FunctionType(b.uintptrType, paramTypes, false)
|
||||
syscallResult := b.CreateCall(fnType, fnPtr, params, "")
|
||||
if isI386 {
|
||||
syscallResult.SetInstructionCallConv(llvm.X86StdcallCallConv)
|
||||
b.writeStackPointer(sp)
|
||||
}
|
||||
|
||||
// err = GetLastError()
|
||||
errResult := b.CreateCall(getLastError.GlobalValueType(), getLastError, nil, "err")
|
||||
if isI386 {
|
||||
errResult.SetInstructionCallConv(llvm.X86StdcallCallConv)
|
||||
}
|
||||
if b.uintptrType != b.ctx.Int32Type() {
|
||||
errResult = b.CreateZExt(errResult, b.uintptrType, "err.uintptr")
|
||||
}
|
||||
|
||||
// Build {r1, 0, err}
|
||||
result := llvm.ConstNull(retType)
|
||||
result = b.CreateInsertValue(result, syscallResult, 0, "")
|
||||
result = b.CreateInsertValue(result, errResult, 2, "")
|
||||
|
||||
incomingVals = append(incomingVals, result)
|
||||
incomingBlocks = append(incomingBlocks, b.Builder.GetInsertBlock())
|
||||
b.CreateBr(mergeBB)
|
||||
}
|
||||
|
||||
// Panic block for n > maxArgs.
|
||||
b.SetInsertPointAtEnd(panicBB)
|
||||
b.CreateUnreachable()
|
||||
|
||||
// Merge block: PHI node to select the result.
|
||||
b.SetInsertPointAtEnd(mergeBB)
|
||||
phi := b.CreatePHI(retType, "syscalln.result")
|
||||
phi.AddIncoming(incomingVals, incomingBlocks)
|
||||
return phi, nil
|
||||
}
|
||||
|
||||
// createRawSyscallNoError emits instructions for the Linux-specific
|
||||
// syscall.rawSyscallNoError function.
|
||||
func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, error) {
|
||||
|
||||
Vendored
+8
@@ -24,6 +24,10 @@ var (
|
||||
x *byte
|
||||
y [61]uintptr
|
||||
}
|
||||
struct5 *struct {
|
||||
x *byte
|
||||
y [30]uintptr
|
||||
}
|
||||
|
||||
slice1 []byte
|
||||
slice2 []*int
|
||||
@@ -58,6 +62,10 @@ func newStruct() {
|
||||
x *byte
|
||||
y [61]uintptr
|
||||
})
|
||||
struct5 = new(struct {
|
||||
x *byte
|
||||
y [30]uintptr
|
||||
})
|
||||
}
|
||||
|
||||
func newFuncValue() *func() {
|
||||
|
||||
Vendored
+8
-4
@@ -16,11 +16,12 @@ target triple = "wasm32-unknown-wasi"
|
||||
@main.struct2 = hidden global ptr null, align 4
|
||||
@main.struct3 = hidden global ptr null, align 4
|
||||
@main.struct4 = hidden global ptr null, align 4
|
||||
@main.struct5 = hidden global ptr null, align 4
|
||||
@main.slice1 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||
@main.slice2 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||
@main.slice3 = hidden global { ptr, i32, i32 } zeroinitializer, align 4
|
||||
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
|
||||
@"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
|
||||
@"runtime/gc.layout:62-0100000000000020" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
|
||||
@"runtime/gc.layout:62-0100000000000000" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
|
||||
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
|
||||
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
|
||||
|
||||
@@ -80,12 +81,15 @@ entry:
|
||||
%new1 = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new1, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new1, ptr @main.struct2, align 4
|
||||
%new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-2000000000000001", ptr undef) #3
|
||||
%new2 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0100000000000020", ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new2, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new2, ptr @main.struct3, align 4
|
||||
%new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0001", ptr undef) #3
|
||||
%new3 = call align 4 dereferenceable(248) ptr @runtime.alloc(i32 248, ptr nonnull @"runtime/gc.layout:62-0100000000000000", ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new3, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new3, ptr @main.struct4, align 4
|
||||
%new4 = call align 4 dereferenceable(124) ptr @runtime.alloc(i32 124, ptr nonnull inttoptr (i32 127 to ptr), ptr undef) #3
|
||||
call void @runtime.trackPointer(ptr nonnull %new4, ptr nonnull %stackalloc, ptr undef) #3
|
||||
store ptr %new4, ptr @main.struct5, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
Vendored
+5
-3
@@ -9,12 +9,14 @@ 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: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: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.signature:Error:func:{}{basic:string}" = linkonce_odr constant i8 0, align 1
|
||||
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, { i32, [1 x ptr] }, [7 x i8] } { i8 116, i16 -32767, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:Error:func:{}{basic:string}"] }, [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: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, { i32, [1 x ptr] } } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature: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:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.signature:String:func:{}{basic:string}" = linkonce_odr constant i8 0, align 1
|
||||
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr, { i32, [1 x ptr] } } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}", { i32, [1 x ptr] } { i32 1, [1 x ptr] [ptr @"reflect/types.signature:String:func:{}{basic:string}"] } }, align 4
|
||||
@"reflect/types.typeid:basic:int" = external constant i8
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
|
||||
Generated
+4
-4
@@ -20,16 +20,16 @@
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1747953325,
|
||||
"narHash": "sha256-y2ZtlIlNTuVJUZCqzZAhIw5rrKP4DOSklev6c8PyCkQ=",
|
||||
"lastModified": 1770136044,
|
||||
"narHash": "sha256-tlFqNG/uzz2++aAmn4v8J0vAkV3z7XngeIIB3rM3650=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "55d1f923c480dadce40f5231feb472e81b0bab48",
|
||||
"rev": "e576e3c9cf9bad747afcddd9e34f51d18c855b4e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-25.05",
|
||||
"ref": "nixos-25.11",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
inputs = {
|
||||
# Use a recent stable release, but fix the version to make it reproducible.
|
||||
# This version should be updated from time to time.
|
||||
nixpkgs.url = "nixpkgs/nixos-25.05";
|
||||
nixpkgs.url = "nixpkgs/nixos-25.11";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
outputs = { self, nixpkgs, flake-utils }:
|
||||
|
||||
@@ -1,29 +1,53 @@
|
||||
module github.com/tinygo-org/tinygo
|
||||
|
||||
go 1.22.0
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
||||
github.com/gofrs/flock v0.8.1
|
||||
github.com/golangci/misspell v0.6.0
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
|
||||
github.com/mattn/go-colorable v0.1.13
|
||||
github.com/mattn/go-tty v0.0.4
|
||||
github.com/mgechev/revive v1.3.9
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
||||
github.com/tetratelabs/wazero v1.6.0
|
||||
go.bug.st/serial v1.6.0
|
||||
github.com/tetratelabs/wazero v1.9.0
|
||||
go.bug.st/serial v1.6.4
|
||||
go.bytecodealliance.org v0.6.2
|
||||
go.bytecodealliance.org/cm v0.2.2
|
||||
golang.org/x/net v0.35.0
|
||||
golang.org/x/sys v0.30.0
|
||||
golang.org/x/tools v0.30.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74
|
||||
tinygo.org/x/espflasher v0.6.0
|
||||
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/chavacava/garif v0.1.0 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/creack/goselect v0.1.2 // indirect
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/fatih/structtag v1.2.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/stretchr/testify v1.8.4 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/regclient/regclient v0.8.2 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1 // indirect
|
||||
golang.org/x/mod v0.23.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
)
|
||||
|
||||
@@ -1,17 +1,36 @@
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139 h1:2O/WuAt8J5id3khcAtVB90czG80m+v0sfkLE07GrCVg=
|
||||
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
|
||||
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
|
||||
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s=
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
@@ -23,18 +42,57 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-tty v0.0.4 h1:NVikla9X8MN0SQAqCYzpGyXv0jY7MNl3HOWD2dkle7E=
|
||||
github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3pxse28=
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
|
||||
github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A=
|
||||
github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/olareg/olareg v0.1.1 h1:Ui7q93zjcoF+U9U71sgqgZWByDoZOpqHitUXEu2xV+g=
|
||||
github.com/olareg/olareg v0.1.1/go.mod h1:w8NP4SWrHHtxsFaUiv1lnCnYPm4sN1seCd2h7FK/dc0=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/regclient/regclient v0.8.2 h1:23BQ3jWgKYHHIXUhp/S9laVJDHDoOQaQCzXMJ4undVE=
|
||||
github.com/regclient/regclient v0.8.2/go.mod h1:uGyetv0o6VLyRDjtfeBqp/QBwRLJ3Hcn07/+8QbhNcM=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
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/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tetratelabs/wazero v1.6.0 h1:z0H1iikCdP8t+q341xqepY4EWvHEw8Es7tlqiVzlP3g=
|
||||
github.com/tetratelabs/wazero v1.6.0/go.mod h1:0U0G41+ochRKoPKCJlh0jMg1CHkyfK8kDqiirMmKY8A=
|
||||
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
|
||||
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
|
||||
go.bug.st/serial v1.6.4 h1:7FmqNPgVp3pu2Jz5PoPtbZ9jJO5gnEnZIvnI1lzve8A=
|
||||
go.bug.st/serial v1.6.4/go.mod h1:nofMJxTeNVny/m6+KaafC6vJGj3miwQZ6vW4BZUGJPI=
|
||||
go.bytecodealliance.org v0.6.2 h1:Jy4u5DVmSkXgsnwojBhJ+AD/YsJsR3VzVnxF0xRCqTQ=
|
||||
go.bytecodealliance.org v0.6.2/go.mod h1:gqjTJm0y9NSksG4py/lSjIQ/SNuIlOQ+hCIEPQwtJgA=
|
||||
go.bytecodealliance.org/cm v0.2.2 h1:M9iHS6qs884mbQbIjtLX1OifgyPG9DuMs2iwz8G4WQA=
|
||||
go.bytecodealliance.org/cm v0.2.2/go.mod h1:JD5vtVNZv7sBoQQkvBvAAVKJPhR/bqBH7yYXTItMfZI=
|
||||
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
|
||||
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
@@ -44,6 +102,7 @@ golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
@@ -56,7 +115,10 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74 h1:ovavgTdIBWCH8YWlcfq9gkpoyT1+IxMKSn+Df27QwE8=
|
||||
tinygo.org/x/go-llvm v0.0.0-20250422114502-b8f170971e74/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||
tinygo.org/x/espflasher v0.6.0 h1:CHbGMHAIWq1tB8FKd/QwBpNFw1jvHHxpmvZiF+QOYUo=
|
||||
tinygo.org/x/espflasher v0.6.0/go.mod h1:tr5u08HoE67WD5zxJesCiiVF/R1b6Akz3yXwh5zah8U=
|
||||
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6 h1:QSnqFgNV2Ij0T4hM2qKv53fcDAFElxClPjVUZXzYkWU=
|
||||
tinygo.org/x/go-llvm v0.0.0-20260422095634-06c6725fe5e6/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const version = "0.40.1"
|
||||
const version = "0.42.0-dev"
|
||||
|
||||
// Return TinyGo version, either in the form 0.30.0 or as a development version
|
||||
// (like 0.30.0-dev-abcd012).
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
// TODO: remove this (by merging it into the top-level go.mod)
|
||||
// once the top level go.mod specifies a go new enough to make our version of misspell happy.
|
||||
|
||||
module tools
|
||||
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/golangci/misspell v0.6.0
|
||||
github.com/mgechev/revive v1.3.9
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v1.4.0 // indirect
|
||||
github.com/chavacava/garif v0.1.0 // indirect
|
||||
github.com/fatih/color v1.17.0 // indirect
|
||||
github.com/fatih/structtag v1.2.0 // indirect
|
||||
github.com/hashicorp/go-version v1.7.0 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.23.0 // indirect
|
||||
)
|
||||
@@ -1,56 +0,0 @@
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/chavacava/garif v0.1.0 h1:2JHa3hbYf5D9dsgseMKAmc/MZ109otzgNFk5s87H9Pc=
|
||||
github.com/chavacava/garif v0.1.0/go.mod h1:XMyYCkEL58DF0oyW4qDjjnPWONs2HBqYKI+UIPD+Gww=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
|
||||
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
|
||||
github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
|
||||
github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
|
||||
github.com/golangci/misspell v0.6.0 h1:JCle2HUTNWirNlDIAUO44hUsKhOFqGPoC4LZxlaSXDs=
|
||||
github.com/golangci/misspell v0.6.0/go.mod h1:keMNyY6R9isGaSAu+4Q8NMBwMPkh15Gtc8UCVoDtAWo=
|
||||
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
|
||||
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517 h1:zpIH83+oKzcpryru8ceC6BxnoG8TBrhgAvRg8obzup0=
|
||||
github.com/mgechev/dots v0.0.0-20210922191527-e955255bf517/go.mod h1:KQ7+USdGKfpPjXk4Ga+5XxQM4Lm4e3gAogrreFAYpOg=
|
||||
github.com/mgechev/revive v1.3.9 h1:18Y3R4a2USSBF+QZKFQwVkBROUda7uoBlkEuBD+YD1A=
|
||||
github.com/mgechev/revive v1.3.9/go.mod h1:+uxEIr5UH0TjXWHTno3xh4u7eg6jDpXKzQccA9UGhHU=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -1,5 +0,0 @@
|
||||
# wasm-tools directory
|
||||
|
||||
This directory has a separate `go.mod` file because the `wasm-tools-go` module requires Go 1.22, while TinyGo itself supports Go 1.19.
|
||||
|
||||
When the minimum Go version for TinyGo is 1.22, this directory can be folded into `internal/tools` and the `go.mod` and `go.sum` files deleted.
|
||||
@@ -1,22 +0,0 @@
|
||||
module github.com/tinygo-org/tinygo/internal/wasm-tools
|
||||
|
||||
go 1.23.0
|
||||
|
||||
require (
|
||||
go.bytecodealliance.org v0.6.2
|
||||
go.bytecodealliance.org/cm v0.2.2
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/regclient/regclient v0.8.2 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/tetratelabs/wazero v1.9.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.12 // indirect
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1 // indirect
|
||||
golang.org/x/mod v0.24.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
)
|
||||
@@ -1,48 +0,0 @@
|
||||
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
|
||||
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
|
||||
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/olareg/olareg v0.1.1 h1:Ui7q93zjcoF+U9U71sgqgZWByDoZOpqHitUXEu2xV+g=
|
||||
github.com/olareg/olareg v0.1.1/go.mod h1:w8NP4SWrHHtxsFaUiv1lnCnYPm4sN1seCd2h7FK/dc0=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/regclient/regclient v0.8.2 h1:23BQ3jWgKYHHIXUhp/S9laVJDHDoOQaQCzXMJ4undVE=
|
||||
github.com/regclient/regclient v0.8.2/go.mod h1:uGyetv0o6VLyRDjtfeBqp/QBwRLJ3Hcn07/+8QbhNcM=
|
||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I=
|
||||
github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM=
|
||||
github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
|
||||
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
|
||||
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
|
||||
go.bytecodealliance.org v0.6.2 h1:Jy4u5DVmSkXgsnwojBhJ+AD/YsJsR3VzVnxF0xRCqTQ=
|
||||
go.bytecodealliance.org v0.6.2/go.mod h1:gqjTJm0y9NSksG4py/lSjIQ/SNuIlOQ+hCIEPQwtJgA=
|
||||
go.bytecodealliance.org/cm v0.2.2 h1:M9iHS6qs884mbQbIjtLX1OifgyPG9DuMs2iwz8G4WQA=
|
||||
go.bytecodealliance.org/cm v0.2.2/go.mod h1:JD5vtVNZv7sBoQQkvBvAAVKJPhR/bqBH7yYXTItMfZI=
|
||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -1,12 +0,0 @@
|
||||
//go:build tools
|
||||
|
||||
// Install tools specified in go.mod.
|
||||
// See https://marcofranssen.nl/manage-go-tools-via-go-modules for idiom.
|
||||
package tools
|
||||
|
||||
import (
|
||||
_ "go.bytecodealliance.org/cm"
|
||||
_ "go.bytecodealliance.org/cmd/wit-bindgen-go"
|
||||
)
|
||||
|
||||
//go:generate go install go.bytecodealliance.org/cmd/wit-bindgen-go
|
||||
+1
-1
@@ -29,7 +29,7 @@ var errInvalidPtrToIntSize = errors.New("interp: ptrtoint integer size does not
|
||||
func isRecoverableError(err error) bool {
|
||||
return err == errIntegerAsPointer || err == errUnsupportedInst ||
|
||||
err == errUnsupportedRuntimeInst || err == errMapAlreadyCreated ||
|
||||
err == errLoopUnrolled
|
||||
err == errLoopUnrolled || err == errInvalidPtrToIntSize
|
||||
}
|
||||
|
||||
// ErrorLine is one line in a traceback. The position may be missing.
|
||||
|
||||
@@ -413,64 +413,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
// Special function that will trigger an error.
|
||||
// This is used to test error reporting.
|
||||
return nil, mem, r.errorAt(inst, errors.New("test error"))
|
||||
case strings.HasSuffix(callFn.name, ".$typeassert"):
|
||||
if r.debug {
|
||||
fmt.Fprintln(os.Stderr, indent+"interface assert:", operands[1:])
|
||||
}
|
||||
|
||||
// Load various values for the interface implements check below.
|
||||
typecodePtr, err := operands[1].asPointer(r)
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
// typecodePtr always point to the numMethod field in the type
|
||||
// description struct. The methodSet, when present, comes right
|
||||
// before the numMethod field (the compiler doesn't generate
|
||||
// method sets for concrete types without methods).
|
||||
// Considering that the compiler doesn't emit interface type
|
||||
// asserts for interfaces with no methods (as the always succeed)
|
||||
// then if the offset is zero, this assert must always fail.
|
||||
if typecodePtr.offset() == 0 {
|
||||
locals[inst.localIndex] = literalValue{uint8(0)}
|
||||
break
|
||||
}
|
||||
typecodePtrOffset, err := typecodePtr.addOffset(-int64(r.pointerSize))
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
methodSetPtr, err := mem.load(typecodePtrOffset, r.pointerSize).asPointer(r)
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
methodSet := mem.get(methodSetPtr.index()).llvmGlobal.Initializer()
|
||||
numMethods := int(r.builder.CreateExtractValue(methodSet, 0, "").ZExtValue())
|
||||
llvmFn := inst.llvmInst.CalledValue()
|
||||
methodSetAttr := llvmFn.GetStringAttributeAtIndex(-1, "tinygo-methods")
|
||||
methodSetString := methodSetAttr.GetStringValue()
|
||||
|
||||
// Make a set of all the methods on the concrete type, for
|
||||
// easier checking in the next step.
|
||||
concreteTypeMethods := map[string]struct{}{}
|
||||
for i := 0; i < numMethods; i++ {
|
||||
methodInfo := r.builder.CreateExtractValue(methodSet, 1, "")
|
||||
name := r.builder.CreateExtractValue(methodInfo, i, "").Name()
|
||||
concreteTypeMethods[name] = struct{}{}
|
||||
}
|
||||
|
||||
// Check whether all interface methods are also in the list
|
||||
// of defined methods calculated above. This is the interface
|
||||
// assert itself.
|
||||
assertOk := uint8(1) // i1 true
|
||||
for _, name := range strings.Split(methodSetString, "; ") {
|
||||
if _, ok := concreteTypeMethods[name]; !ok {
|
||||
// There is a method on the interface that is not
|
||||
// implemented by the type. The assertion will fail.
|
||||
assertOk = 0 // i1 false
|
||||
break
|
||||
}
|
||||
}
|
||||
// If assertOk is still 1, the assertion succeeded.
|
||||
locals[inst.localIndex] = literalValue{assertOk}
|
||||
case strings.HasSuffix(callFn.name, "$invoke"):
|
||||
// This thunk is the interface method dispatcher: it is called
|
||||
// with all regular parameters and a type code. It will then
|
||||
|
||||
+1
-1
Submodule lib/stm32-svd updated: e6db8e32d5...bfed180b63
@@ -245,6 +245,7 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
|
||||
"internal/cm/": false,
|
||||
"internal/futex/": false,
|
||||
"internal/fuzz/": false,
|
||||
"internal/itoa": false,
|
||||
"internal/reflectlite/": false,
|
||||
"internal/gclayout": false,
|
||||
"internal/task/": false,
|
||||
@@ -267,11 +268,31 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
|
||||
paths["crypto/internal/boring/sig/"] = false
|
||||
}
|
||||
|
||||
if goMinor >= 26 {
|
||||
// Go 1.26 added a CPU jitter entropy source for FIPS 140-3 that
|
||||
// allocates a 32 MiB global buffer (ScratchBuffer [1<<25]byte).
|
||||
// This is fine on systems with virtual memory, but causes RAM
|
||||
// overflow on microcontrollers. Replace with a zero-size stub
|
||||
// since TinyGo targets never use FIPS jitter entropy.
|
||||
paths["crypto/internal/entropy/"] = true
|
||||
paths["crypto/internal/entropy/v1.0.0/"] = false
|
||||
}
|
||||
|
||||
if needsSyscallPackage {
|
||||
paths["syscall/"] = true // include syscall/js
|
||||
paths["internal/syscall/"] = true
|
||||
paths["internal/syscall/unix/"] = false
|
||||
}
|
||||
|
||||
if goMinor >= 26 {
|
||||
// Go 1.26 added SWAR optimizations to unicode/utf8 that use
|
||||
// constants assuming at least 32-bit uintptr. TinyGo supports
|
||||
// 16-bit targets (AVR) where these constants overflow, so we
|
||||
// provide a patched version.
|
||||
paths["unicode/"] = true
|
||||
paths["unicode/utf8/"] = false
|
||||
}
|
||||
|
||||
return paths
|
||||
}
|
||||
|
||||
|
||||
+55
-41
@@ -549,7 +549,7 @@ func (p *Package) extractEmbedLines(addError func(error)) {
|
||||
}
|
||||
|
||||
// Look for //go:embed comments.
|
||||
var allPatterns []string
|
||||
var allPatterns []embedPattern
|
||||
for _, comment := range doc.List {
|
||||
if comment.Text != "//go:embed" && !strings.HasPrefix(comment.Text, "//go:embed ") {
|
||||
continue
|
||||
@@ -577,21 +577,7 @@ func (p *Package) extractEmbedLines(addError func(error)) {
|
||||
})
|
||||
continue
|
||||
}
|
||||
for _, pattern := range patterns {
|
||||
// Check that the pattern is well-formed.
|
||||
// It must be valid: the Go toolchain has already
|
||||
// checked for invalid patterns. But let's check
|
||||
// anyway to be sure.
|
||||
if _, err := path.Match(pattern, ""); err != nil {
|
||||
addError(types.Error{
|
||||
Fset: p.program.fset,
|
||||
Pos: comment.Pos(),
|
||||
Msg: "invalid pattern syntax",
|
||||
})
|
||||
continue
|
||||
}
|
||||
allPatterns = append(allPatterns, pattern)
|
||||
}
|
||||
allPatterns = append(allPatterns, patterns...)
|
||||
}
|
||||
|
||||
if len(allPatterns) != 0 {
|
||||
@@ -624,8 +610,8 @@ func (p *Package) extractEmbedLines(addError func(error)) {
|
||||
// Match all //go:embed patterns against the embed files
|
||||
// provided by `go list`.
|
||||
for _, name := range p.EmbedFiles {
|
||||
for _, pattern := range allPatterns {
|
||||
if matchPattern(pattern, name) {
|
||||
for _, ep := range allPatterns {
|
||||
if ep.Match(name) {
|
||||
p.EmbedGlobals[globalName] = append(p.EmbedGlobals[globalName], &EmbedFile{
|
||||
Name: name,
|
||||
NeedsData: byteSlice,
|
||||
@@ -641,13 +627,37 @@ func (p *Package) extractEmbedLines(addError func(error)) {
|
||||
}
|
||||
}
|
||||
|
||||
// matchPattern returns true if (and only if) the given pattern would match the
|
||||
// filename. The pattern could also match a parent directory of name, in which
|
||||
// case hidden files do not match.
|
||||
func matchPattern(pattern, name string) bool {
|
||||
// embedPattern represents a valid //go:embed pattern.
|
||||
// See: https://pkg.go.dev/embed#hdr-Directives
|
||||
type embedPattern struct {
|
||||
pattern string // glob pattern without "all:" prefix
|
||||
includeHidden bool // true if "all:" prefix was present
|
||||
}
|
||||
|
||||
// newEmbedPattern parses and validates a //go:embed pattern.
|
||||
// The "all:" prefix (if present) is stripped and reflected in includeHidden.
|
||||
// Returns an error if the pattern syntax is invalid.
|
||||
func newEmbedPattern(s string) (embedPattern, error) {
|
||||
ep := embedPattern{pattern: s}
|
||||
if strings.HasPrefix(s, "all:") {
|
||||
ep.pattern = s[4:]
|
||||
ep.includeHidden = true
|
||||
}
|
||||
if _, err := path.Match(ep.pattern, ""); err != nil {
|
||||
return embedPattern{}, err
|
||||
}
|
||||
return ep, nil
|
||||
}
|
||||
|
||||
// Match returns true if (and only if) the pattern matches the given filename.
|
||||
// The pattern could also match a parent directory of name, in which case hidden
|
||||
// files do not match (unless includeHidden is true).
|
||||
func (ep embedPattern) Match(name string) bool {
|
||||
pattern := ep.pattern
|
||||
includeHidden := ep.includeHidden
|
||||
|
||||
// Match this file.
|
||||
matched, _ := path.Match(pattern, name)
|
||||
if matched {
|
||||
if matched, _ := path.Match(pattern, name); matched {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -661,17 +671,20 @@ func matchPattern(pattern, name string) bool {
|
||||
dir = path.Clean(dir)
|
||||
if matched, _ := path.Match(pattern, dir); matched {
|
||||
// Pattern matches the directory.
|
||||
suffix := name[len(dir):]
|
||||
if strings.Contains(suffix, "/_") || strings.Contains(suffix, "/.") {
|
||||
// Pattern matches a hidden file.
|
||||
// Hidden files are included when listed directly as a
|
||||
// pattern, but not when they are part of a directory tree.
|
||||
// Source:
|
||||
// > If a pattern names a directory, all files in the
|
||||
// > subtree rooted at that directory are embedded
|
||||
// > (recursively), except that files with names beginning
|
||||
// > with ‘.’ or ‘_’ are excluded.
|
||||
return false
|
||||
if !includeHidden {
|
||||
suffix := name[len(dir):]
|
||||
if strings.Contains(suffix, "/_") || strings.Contains(suffix, "/.") {
|
||||
// Pattern matches a hidden file.
|
||||
// Hidden files are included when listed directly as a
|
||||
// pattern, or when the "all:" prefix is used, but not
|
||||
// when they are part of a directory tree without "all:".
|
||||
// Source:
|
||||
// > If a pattern names a directory, all files in the
|
||||
// > subtree rooted at that directory are embedded
|
||||
// > (recursively), except that files with names beginning
|
||||
// > with ‘.’ or ‘_’ are excluded.
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@@ -680,11 +693,12 @@ func matchPattern(pattern, name string) bool {
|
||||
|
||||
// parseGoEmbed is like strings.Fields but for a //go:embed line. It parses
|
||||
// regular fields and quoted fields (that may contain spaces).
|
||||
func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []string, err error) {
|
||||
func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []embedPattern, err error) {
|
||||
args = strings.TrimSpace(args)
|
||||
initialLen := len(args)
|
||||
for args != "" {
|
||||
patternPos := pos + token.Pos(initialLen-len(args))
|
||||
var pattern string
|
||||
switch args[0] {
|
||||
case '`', '"', '\\':
|
||||
// Parse the next pattern using the Go scanner.
|
||||
@@ -703,8 +717,7 @@ func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []string, e
|
||||
Msg: "invalid quoted string in //go:embed",
|
||||
}
|
||||
}
|
||||
pattern := constant.StringVal(constant.MakeFromLiteral(lit, tok, 0))
|
||||
patterns = append(patterns, pattern)
|
||||
pattern = constant.StringVal(constant.MakeFromLiteral(lit, tok, 0))
|
||||
args = strings.TrimLeftFunc(args[len(lit):], unicode.IsSpace)
|
||||
default:
|
||||
// The value is just a regular value.
|
||||
@@ -713,17 +726,18 @@ func (p *Package) parseGoEmbed(args string, pos token.Pos) (patterns []string, e
|
||||
if index < 0 {
|
||||
index = len(args)
|
||||
}
|
||||
pattern := args[:index]
|
||||
patterns = append(patterns, pattern)
|
||||
pattern = args[:index]
|
||||
args = strings.TrimLeftFunc(args[len(pattern):], unicode.IsSpace)
|
||||
}
|
||||
if _, err := path.Match(patterns[len(patterns)-1], ""); err != nil {
|
||||
ep, err := newEmbedPattern(pattern)
|
||||
if err != nil {
|
||||
return nil, types.Error{
|
||||
Fset: p.program.fset,
|
||||
Pos: patternPos,
|
||||
Msg: "invalid pattern syntax",
|
||||
}
|
||||
}
|
||||
patterns = append(patterns, ep)
|
||||
}
|
||||
return patterns, nil
|
||||
}
|
||||
|
||||
+1
-3
@@ -8,9 +8,7 @@ import (
|
||||
//
|
||||
// The program must already be parsed and type-checked with the .Parse() method.
|
||||
func (p *Program) LoadSSA() *ssa.Program {
|
||||
// TODO: re-enable SanityCheckFunctions when x/tools is upgraded to
|
||||
// a version with a fix for https://golang.org/issues/73594.
|
||||
prog := ssa.NewProgram(p.fset /*ssa.SanityCheckFunctions|*/, ssa.BareInits|ssa.GlobalDebug|ssa.InstantiateGenerics)
|
||||
prog := ssa.NewProgram(p.fset, ssa.SanityCheckFunctions|ssa.BareInits|ssa.GlobalDebug|ssa.InstantiateGenerics)
|
||||
|
||||
for _, pkg := range p.sorted {
|
||||
prog.CreatePackage(pkg.Pkg, pkg.Files, &pkg.info, true)
|
||||
|
||||
@@ -32,12 +32,15 @@ import (
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
"github.com/tinygo-org/tinygo/loader"
|
||||
"golang.org/x/tools/go/buildutil"
|
||||
"tinygo.org/x/espflasher/pkg/espflasher"
|
||||
"tinygo.org/x/go-llvm"
|
||||
|
||||
"go.bug.st/serial"
|
||||
"go.bug.st/serial/enumerator"
|
||||
)
|
||||
|
||||
var errInheritableOnly = errors.New("target is inheritable-only, which means it cannot be used directly for building or flashing")
|
||||
|
||||
// commandError is an error type to wrap os/exec.Command errors. This provides
|
||||
// some more information regarding what went wrong while running a command.
|
||||
type commandError struct {
|
||||
@@ -139,6 +142,10 @@ func printCommand(cmd string, args ...string) {
|
||||
|
||||
// Build compiles and links the given package and writes it to outpath.
|
||||
func Build(pkgName, outpath string, config *compileopts.Config) error {
|
||||
if config.Target != nil && config.Target.InheritableOnly {
|
||||
return errInheritableOnly
|
||||
}
|
||||
|
||||
// Create a temporary directory for intermediary files.
|
||||
tmpdir, err := os.MkdirTemp("", "tinygo")
|
||||
if err != nil {
|
||||
@@ -356,6 +363,10 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.Target != nil && config.Target.InheritableOnly {
|
||||
return errInheritableOnly
|
||||
}
|
||||
|
||||
// determine the type of file to compile
|
||||
var fileExt string
|
||||
|
||||
@@ -385,6 +396,10 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
|
||||
fileExt = ".hex"
|
||||
case "bmp":
|
||||
fileExt = ".elf"
|
||||
case "adb":
|
||||
fileExt = ".hex"
|
||||
case "esp32flash", "esp32jtag":
|
||||
fileExt = ".bin"
|
||||
case "native":
|
||||
return errors.New("unknown flash method \"native\" - did you miss a -target flag?")
|
||||
default:
|
||||
@@ -519,6 +534,56 @@ func Flash(pkgName, port, outpath string, options *compileopts.Options) error {
|
||||
if err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
}
|
||||
case "adb":
|
||||
// Run pre-flash adb shell commands.
|
||||
for _, preCmd := range config.Target.ADBPreCommands {
|
||||
cmd := executeCommand(config.Options, "adb", "shell", preCmd)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return &commandError{"failed to run adb pre-command", preCmd, err}
|
||||
}
|
||||
}
|
||||
|
||||
// Push the binary to the device.
|
||||
if config.Target.ADBPushRemote == "" {
|
||||
return errors.New("invalid target file: flash-method was set to \"adb\" but no adb-push-remote was set")
|
||||
}
|
||||
cmd := executeCommand(config.Options, "adb", "push", result.Binary, config.Target.ADBPushRemote)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return &commandError{"adb push failed to " + config.Target.ADBPushRemote, result.Binary, err}
|
||||
}
|
||||
|
||||
// Run post-flash adb shell commands.
|
||||
for _, postCmd := range config.Target.ADBPostCommands {
|
||||
postCmd = strings.ReplaceAll(postCmd, "{remote}", config.Target.ADBPushRemote)
|
||||
cmd := executeCommand(config.Options, "adb", "shell", postCmd)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if err := cmd.Run(); err != nil {
|
||||
return &commandError{"failed to run adb post-command", postCmd, err}
|
||||
}
|
||||
}
|
||||
case "esp32flash":
|
||||
port, err := getDefaultPort(port, config.Target.SerialPort)
|
||||
if err != nil {
|
||||
return &commandError{"failed to find port", port, err}
|
||||
}
|
||||
|
||||
if err := flashBinUsingEsp32(port, classicReset, result.Binary, config.Options); err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
}
|
||||
case "esp32jtag":
|
||||
port, err := getDefaultPort(port, config.Target.SerialPort)
|
||||
if err != nil {
|
||||
return &commandError{"failed to find port", port, err}
|
||||
}
|
||||
|
||||
if err := flashBinUsingEsp32(port, jtagReset, result.Binary, config.Options); err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown flash method: %s", flashMethod)
|
||||
}
|
||||
@@ -765,6 +830,10 @@ func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if config.Target != nil && config.Target.InheritableOnly {
|
||||
return errInheritableOnly
|
||||
}
|
||||
|
||||
_, err = buildAndRun(pkgName, config, os.Stdout, cmdArgs, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
return cmd.Run()
|
||||
})
|
||||
@@ -1019,6 +1088,68 @@ func flashHexUsingMSD(volumes []string, tmppath string, options *compileopts.Opt
|
||||
return errors.New("unable to locate any volume: [" + strings.Join(volumes, ",") + "]")
|
||||
}
|
||||
|
||||
const (
|
||||
defaultReset = "default"
|
||||
classicReset = "classic"
|
||||
jtagReset = "jtag"
|
||||
)
|
||||
|
||||
func flashBinUsingEsp32(port, resetMode, tmppath string, options *compileopts.Options) error {
|
||||
opts := espflasher.DefaultOptions()
|
||||
opts.Compress = true
|
||||
opts.Logger = &espflasher.StdoutLogger{W: os.Stdout}
|
||||
if options.BaudRate != 0 {
|
||||
opts.FlashBaudRate = options.BaudRate
|
||||
}
|
||||
|
||||
if resetMode == jtagReset {
|
||||
opts.ResetMode = espflasher.ResetUSBJTAG
|
||||
}
|
||||
|
||||
flasher, err := espflasher.New(port, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer flasher.Close()
|
||||
|
||||
chipName := flasher.ChipName()
|
||||
offset := uint32(0x0)
|
||||
if chipName == "ESP32" {
|
||||
offset = 0x1000
|
||||
}
|
||||
|
||||
// Read the firmware binary
|
||||
data, err := os.ReadFile(tmppath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := flasher.EraseFlash(); err != nil {
|
||||
return fmt.Errorf("erase failed: %v", err)
|
||||
}
|
||||
|
||||
progress := func(current, total int) {
|
||||
pct := float64(current) / float64(total) * 100
|
||||
bar := int(pct / 2)
|
||||
fmt.Printf("\r[%-50s] %6.1f%%", strings.Repeat("#", bar)+strings.Repeat(".", 50-bar), pct)
|
||||
if current >= total {
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
// Flash with progress reporting
|
||||
err = flasher.FlashImage(data, offset, progress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println()
|
||||
|
||||
// Reset the device to run the new firmware
|
||||
flasher.Reset()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type mountPoint struct {
|
||||
name string
|
||||
path string
|
||||
|
||||
+4
-1
@@ -107,6 +107,9 @@ func TestBuild(t *testing.T) {
|
||||
if minor >= 23 {
|
||||
tests = append(tests, "go1.23/")
|
||||
}
|
||||
if minor >= 24 {
|
||||
tests = append(tests, "typealias.go")
|
||||
}
|
||||
|
||||
if *testTarget != "" {
|
||||
// This makes it possible to run one specific test (instead of all),
|
||||
@@ -451,7 +454,7 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
|
||||
// Build the test binary.
|
||||
stdout := &bytes.Buffer{}
|
||||
_, err = buildAndRun(pkgName, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
_, err = buildAndRun(pkgName, config, stdout, cmdArgs, environmentVars, 2*time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
return cmd.Run()
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2025 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Stripped-down version of the entropy package for TinyGo.
|
||||
//
|
||||
// The upstream Go 1.26 package allocates a [1<<25]byte (32 MiB) global buffer
|
||||
// for CPU jitter-based SP 800-90B entropy collection. This is fine on systems
|
||||
// with virtual memory where BSS pages are lazily backed, but it causes a fatal
|
||||
// "RAM overflowed" error on microcontrollers and other memory-constrained
|
||||
// targets.
|
||||
//
|
||||
// Because FIPS 140-3 jitter entropy is never used on TinyGo targets (the DRBG
|
||||
// falls through to sysrand.Read when fips140.Enabled is false), this overlay
|
||||
// replaces the 32 MiB buffer with a zero-size type.
|
||||
package entropy
|
||||
|
||||
// Version returns the version of the entropy source.
|
||||
func Version() string {
|
||||
return "v1.0.0"
|
||||
}
|
||||
|
||||
// ScratchBuffer is a large buffer in upstream Go (32 MiB). TinyGo replaces it
|
||||
// with a zero-size type since the CPU jitter entropy source is not used.
|
||||
type ScratchBuffer [0]byte
|
||||
|
||||
// Seed returns a 384-bit seed with full entropy.
|
||||
// On TinyGo targets this is never called because FIPS mode is not enabled.
|
||||
func Seed(memory *ScratchBuffer) ([48]byte, error) {
|
||||
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
|
||||
}
|
||||
|
||||
// Samples collects entropy samples. Not supported on TinyGo targets.
|
||||
func Samples(samples []uint8, memory *ScratchBuffer) error {
|
||||
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
|
||||
}
|
||||
|
||||
// SHA384 computes SHA-384 over 1024 bytes. Not supported on TinyGo targets.
|
||||
func SHA384(p *[1024]byte) [48]byte {
|
||||
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
|
||||
}
|
||||
|
||||
// TestingOnlySHA384 computes SHA-384 over arbitrary bytes. Not supported on TinyGo targets.
|
||||
func TestingOnlySHA384(p []byte) [48]byte {
|
||||
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
|
||||
}
|
||||
|
||||
// RepetitionCountTest implements the repetition count test from SP 800-90B.
|
||||
func RepetitionCountTest(samples []uint8) error {
|
||||
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
|
||||
}
|
||||
|
||||
// AdaptiveProportionTest implements the adaptive proportion test from SP 800-90B.
|
||||
func AdaptiveProportionTest(samples []uint8) error {
|
||||
panic("entropy: CPU jitter entropy source is not supported on TinyGo targets")
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey || (tinygo.riscv32 && virt)
|
||||
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || esp32s3 || tkey || (tinygo.riscv32 && virt)
|
||||
|
||||
// If you update the above build constraint, you'll probably also need to update
|
||||
// src/runtime/rand_hwrng.go.
|
||||
|
||||
@@ -0,0 +1,397 @@
|
||||
// Startup code for the ESP32-S3 (Xtensa LX7, windowed ABI).
|
||||
//
|
||||
// The ROM bootloader loads IRAM/DRAM segments into SRAM but does NOT
|
||||
// configure flash cache/MMU. We must:
|
||||
// 1. Set up the windowed-ABI register file and stack pointer.
|
||||
// 2. Set VECBASE and clear PS.EXCM (needed for callx4 window overflows).
|
||||
// 3. Disable watchdog timers.
|
||||
// 4. Configure the flash cache and MMU so IROM/DROM are accessible.
|
||||
// 5. Jump to runtime.main (in IROM).
|
||||
//
|
||||
// Cache/MMU init sequence (from NuttX esp_loader.c / ESP-IDF bootloader / esp-hal):
|
||||
// Phase A — configure cache modes:
|
||||
// a. rom_config_instruction_cache_mode(16KB, 8-way, 32B)
|
||||
// b. rom_Cache_Suspend_DCache()
|
||||
// c. rom_config_data_cache_mode(32KB, 8-way, 32B)
|
||||
// d. Cache_Resume_DCache(0)
|
||||
// Phase B — map flash pages:
|
||||
// e. Disable caches
|
||||
// f. Cache_MMU_Init() — reset all MMU entries to invalid
|
||||
// g. Cache_Set_IDROM_MMU_Size() — set IROM/DROM entry split
|
||||
// h. Write MMU entries mapping flash page 0 for IROM and DROM
|
||||
// i. Clear bus-shut bits
|
||||
// j. Enable caches + isync
|
||||
|
||||
#define PS_WOE 0x00040000
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Boot entry point — placed in IRAM by the linker.
|
||||
// -----------------------------------------------------------------------
|
||||
.section .text.call_start_cpu0
|
||||
.literal_position
|
||||
.align 4
|
||||
.Lstack_top_addr:
|
||||
.long _stack_top
|
||||
.Lmain_addr:
|
||||
.long main
|
||||
.Lvector_table_addr:
|
||||
.long _vector_table
|
||||
// WDT register addresses
|
||||
.Lwdt_key:
|
||||
.long 0x50D83AA1
|
||||
.Lrtc_wdt_protect:
|
||||
.long 0x600080B0
|
||||
.Lrtc_wdt_config0:
|
||||
.long 0x60008098
|
||||
.Ltimg0_wdt_protect:
|
||||
.long 0x6001F064
|
||||
.Ltimg0_wdt_config0:
|
||||
.long 0x6001F048
|
||||
.Ltimg1_wdt_protect:
|
||||
.long 0x60020064
|
||||
.Ltimg1_wdt_config0:
|
||||
.long 0x60020048
|
||||
.Lswd_protect:
|
||||
.long 0x600080B8
|
||||
.Lswd_key:
|
||||
.long 0x8F1D312A
|
||||
.Lswd_conf:
|
||||
.long 0x600080B4
|
||||
.Lswd_disable:
|
||||
.long 0x40000000
|
||||
// ROM function addresses (from ESP-IDF esp32s3.rom.ld)
|
||||
.Lrom_config_icache:
|
||||
.long 0x40001a1c
|
||||
.Lrom_config_dcache:
|
||||
.long 0x40001a28
|
||||
.Lrom_suspend_dcache:
|
||||
.long 0x400018b4
|
||||
.LCache_Resume_DCache:
|
||||
.long 0x400018c0
|
||||
.LCache_Disable_ICache:
|
||||
.long 0x4000186c
|
||||
.LCache_Disable_DCache:
|
||||
.long 0x40001884
|
||||
.LCache_MMU_Init:
|
||||
.long 0x40001998
|
||||
.LCache_Set_IDROM_MMU_Size:
|
||||
.long 0x40001914
|
||||
.LCache_Enable_ICache:
|
||||
.long 0x40001878
|
||||
.LCache_Enable_DCache:
|
||||
.long 0x40001890
|
||||
// Cache/MMU register addresses
|
||||
.Lmmu_table_base:
|
||||
.long 0x600C5000
|
||||
.Licache_ctrl1_reg:
|
||||
.long 0x600C4064
|
||||
.Ldcache_ctrl1_reg:
|
||||
.long 0x600C4004
|
||||
// End-of-section symbols for multi-page MMU mapping.
|
||||
.Lirom_end:
|
||||
.long _irom_end
|
||||
.Ldrom_end:
|
||||
.long _drom_end
|
||||
.Lirom_base:
|
||||
.long 0x42000000
|
||||
.Ldrom_base:
|
||||
.long 0x3C000000
|
||||
|
||||
.global call_start_cpu0
|
||||
call_start_cpu0:
|
||||
|
||||
// ---- 1. Windowed-ABI register file setup ----
|
||||
|
||||
// Disable WOE so we can safely manipulate WINDOWSTART.
|
||||
rsr.ps a2
|
||||
movi a3, ~(PS_WOE)
|
||||
and a2, a2, a3
|
||||
wsr.ps a2
|
||||
rsync
|
||||
|
||||
// Set WINDOWSTART to 1 << WINDOWBASE (mark only current window as valid).
|
||||
rsr.windowbase a2
|
||||
ssl a2
|
||||
movi a2, 1
|
||||
sll a2, a2
|
||||
wsr.windowstart a2
|
||||
rsync
|
||||
|
||||
// Load stack pointer.
|
||||
l32r a1, .Lstack_top_addr
|
||||
|
||||
// Re-enable WOE.
|
||||
rsr.ps a2
|
||||
movi a3, PS_WOE
|
||||
or a2, a2, a3
|
||||
wsr.ps a2
|
||||
rsync
|
||||
|
||||
// Enable FPU (coprocessor 0).
|
||||
movi a2, 1
|
||||
wsr.cpenable a2
|
||||
rsync
|
||||
|
||||
// ---- 2. Disable all watchdog timers (IMMEDIATELY, before any delay) ----
|
||||
l32r a3, .Lwdt_key
|
||||
movi a4, 0
|
||||
|
||||
// RTC WDT
|
||||
l32r a2, .Lrtc_wdt_protect
|
||||
memw
|
||||
s32i a3, a2, 0
|
||||
l32r a5, .Lrtc_wdt_config0
|
||||
memw
|
||||
s32i a4, a5, 0
|
||||
memw
|
||||
s32i a4, a2, 0
|
||||
|
||||
// TIMG0 WDT
|
||||
l32r a2, .Ltimg0_wdt_protect
|
||||
memw
|
||||
s32i a3, a2, 0
|
||||
l32r a5, .Ltimg0_wdt_config0
|
||||
memw
|
||||
s32i a4, a5, 0
|
||||
memw
|
||||
s32i a4, a2, 0
|
||||
|
||||
// TIMG1 WDT
|
||||
l32r a2, .Ltimg1_wdt_protect
|
||||
memw
|
||||
s32i a3, a2, 0
|
||||
l32r a5, .Ltimg1_wdt_config0
|
||||
memw
|
||||
s32i a4, a5, 0
|
||||
memw
|
||||
s32i a4, a2, 0
|
||||
|
||||
// Super WDT
|
||||
l32r a2, .Lswd_protect
|
||||
l32r a3, .Lswd_key
|
||||
memw
|
||||
s32i a3, a2, 0
|
||||
l32r a5, .Lswd_conf
|
||||
l32r a6, .Lswd_disable
|
||||
memw
|
||||
s32i a6, a5, 0
|
||||
memw
|
||||
s32i a4, a2, 0
|
||||
|
||||
// ---- 3. Set VECBASE and clear PS.EXCM ----
|
||||
// VECBASE must be set before any callx4 so that window overflow
|
||||
// exceptions (triggered by register window rotation) route to our
|
||||
// handlers in IRAM, not the ROM's default vectors.
|
||||
l32r a8, .Lvector_table_addr
|
||||
wsr.vecbase a8
|
||||
rsync
|
||||
|
||||
// Clear PS.EXCM (bit 4) and PS.INTLEVEL (bits 0-3).
|
||||
// The ROM bootloader may leave EXCM=1; with EXCM set any callx4
|
||||
// window overflow would become a double exception.
|
||||
// Set PS.UM (bit 5) so level-1 exceptions route to User vector.
|
||||
rsr.ps a2
|
||||
movi a3, ~0x1F
|
||||
and a2, a2, a3
|
||||
movi a3, 0x20
|
||||
or a2, a2, a3
|
||||
wsr.ps a2
|
||||
rsync
|
||||
|
||||
// ---- 4. Configure flash cache and MMU ----
|
||||
//
|
||||
// ROM function calls use callx4 (windowed ABI):
|
||||
// a4 = target address (overwritten with return addr by call mechanism)
|
||||
// a5 = stack pointer for callee (becomes callee's a1 via entry)
|
||||
// a6 = first argument (becomes callee's a2)
|
||||
// a7 = second argument (becomes callee's a3)
|
||||
// a8 = third argument (becomes callee's a4)
|
||||
// Registers a0-a3 are preserved across callx4; a4-a11 may be clobbered.
|
||||
|
||||
// Phase A: Configure cache modes (required for cache hardware to function).
|
||||
// Without this, the cache doesn't know its size/associativity/line-size
|
||||
// and cannot service flash accesses.
|
||||
|
||||
// 4a. Configure ICache mode: 16KB, 8-way, 32-byte line
|
||||
movi a6, 0x4000 // cache_size = 16KB
|
||||
movi a7, 8 // ways = 8
|
||||
movi a8, 32 // line_size = 32
|
||||
mov a5, a1
|
||||
l32r a4, .Lrom_config_icache
|
||||
callx4 a4
|
||||
|
||||
// 4b. Suspend DCache before configuring it
|
||||
mov a5, a1
|
||||
l32r a4, .Lrom_suspend_dcache
|
||||
callx4 a4
|
||||
|
||||
// 4c. Configure DCache mode: 32KB, 8-way, 32-byte line
|
||||
movi a6, 0x8000 // cache_size = 32KB
|
||||
movi a7, 8 // ways = 8
|
||||
movi a8, 32 // line_size = 32
|
||||
mov a5, a1
|
||||
l32r a4, .Lrom_config_dcache
|
||||
callx4 a4
|
||||
|
||||
// 4d. Resume DCache
|
||||
movi a6, 0
|
||||
mov a5, a1
|
||||
l32r a4, .LCache_Resume_DCache
|
||||
callx4 a4
|
||||
|
||||
// Phase B: Map flash pages into MMU.
|
||||
|
||||
// 4e. Disable ICache
|
||||
mov a5, a1
|
||||
l32r a4, .LCache_Disable_ICache
|
||||
callx4 a4
|
||||
|
||||
// 4f. Disable DCache
|
||||
mov a5, a1
|
||||
l32r a4, .LCache_Disable_DCache
|
||||
callx4 a4
|
||||
|
||||
// 4g. Initialize MMU (resets all 512 entries to invalid = 0x4000)
|
||||
mov a5, a1
|
||||
l32r a4, .LCache_MMU_Init
|
||||
callx4 a4
|
||||
|
||||
// 4h. Set IDROM MMU size: even 256/256 split.
|
||||
// Each entry is 4 bytes, so 256 entries = 0x400 bytes per region.
|
||||
movi a6, 0x400 // irom_mmu_size (256 entries × 4 bytes)
|
||||
movi a7, 0x400 // drom_mmu_size (256 entries × 4 bytes)
|
||||
mov a5, a1
|
||||
l32r a4, .LCache_Set_IDROM_MMU_Size
|
||||
callx4 a4
|
||||
|
||||
// 4i. Map flash pages for IROM and DROM using identity mapping.
|
||||
// MMU table at 0x600C5000: entries 0-255 = ICache, 256-511 = DCache.
|
||||
// Entry value N = flash page N (SOC_MMU_VALID = 0 on S3).
|
||||
// Each 64KB page needs one 4-byte entry.
|
||||
//
|
||||
// IROM: map pages 0..N where N = (_irom_end - 0x42000000) >> 16
|
||||
// DROM: map pages 0..M where M = (_drom_end - 0x3C000000) >> 16
|
||||
|
||||
l32r a8, .Lmmu_table_base // a8 = 0x600C5000
|
||||
|
||||
// --- IROM pages ---
|
||||
l32r a2, .Lirom_end // a2 = _irom_end (VMA in 0x42xxxxxx)
|
||||
l32r a3, .Lirom_base // a3 = 0x42000000
|
||||
sub a2, a2, a3 // a2 = byte offset past IROM base
|
||||
srli a2, a2, 16 // a2 = last page index
|
||||
addi a2, a2, 1 // a2 = number of pages to map
|
||||
movi a9, 0 // a9 = page counter (and entry value)
|
||||
mov a10, a8 // a10 = current MMU entry pointer
|
||||
.Lirom_loop:
|
||||
s32i a9, a10, 0
|
||||
addi a9, a9, 1
|
||||
addi a10, a10, 4
|
||||
blt a9, a2, .Lirom_loop
|
||||
|
||||
// --- DROM pages ---
|
||||
l32r a2, .Ldrom_end // a2 = _drom_end (VMA in 0x3Cxxxxxx)
|
||||
l32r a3, .Ldrom_base // a3 = 0x3C000000
|
||||
sub a2, a2, a3 // a2 = byte offset past DROM base
|
||||
srli a2, a2, 16 // a2 = last page index
|
||||
addi a2, a2, 1 // a2 = number of pages to map
|
||||
movi a9, 0 // a9 = page counter (and entry value)
|
||||
addmi a10, a8, 0x400 // a10 = 0x600C5400 (DCache entry 256)
|
||||
.Ldrom_loop:
|
||||
s32i a9, a10, 0
|
||||
addi a9, a9, 1
|
||||
addi a10, a10, 4
|
||||
blt a9, a2, .Ldrom_loop
|
||||
memw
|
||||
|
||||
// 4j. Clear bus-shut bits so core 0 can access ICache and DCache buses.
|
||||
l32r a8, .Licache_ctrl1_reg // 0x600C4064
|
||||
movi a9, 0
|
||||
s32i a9, a8, 0 // Clear all ICACHE_CTRL1 shut bits
|
||||
l32r a8, .Ldcache_ctrl1_reg // 0x600C4004
|
||||
s32i a9, a8, 0 // Clear all DCACHE_CTRL1 shut bits
|
||||
memw
|
||||
|
||||
// 4k. Enable ICache (arg: autoload = 0)
|
||||
movi a6, 0
|
||||
mov a5, a1
|
||||
l32r a4, .LCache_Enable_ICache
|
||||
callx4 a4
|
||||
|
||||
// 4l. Enable DCache (arg: autoload = 0)
|
||||
movi a6, 0
|
||||
mov a5, a1
|
||||
l32r a4, .LCache_Enable_DCache
|
||||
callx4 a4
|
||||
|
||||
// Flush instruction pipeline so new cache/MMU config takes effect.
|
||||
isync
|
||||
|
||||
// ---- 5. Jump to main (in IROM) ----
|
||||
// Re-clear PS.EXCM in case ROM calls changed processor state.
|
||||
rsr.ps a2
|
||||
movi a3, ~0x1F
|
||||
and a2, a2, a3
|
||||
movi a3, 0x20
|
||||
or a2, a2, a3
|
||||
wsr.ps a2
|
||||
rsync
|
||||
|
||||
mov a5, a1
|
||||
l32r a4, .Lmain_addr
|
||||
callx4 a4
|
||||
|
||||
// If main returns, loop forever.
|
||||
1: j 1b
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// tinygo_scanCurrentStack — Spill all Xtensa register windows to the
|
||||
// stack, then call tinygo_scanstack(sp) so the conservative GC can
|
||||
// discover live heap pointers that are currently in physical registers.
|
||||
//
|
||||
// On RISC-V / ARM the equivalent function pushes callee-saved registers
|
||||
// before the call. On Xtensa windowed ABI the same effect is achieved
|
||||
// by forcing hardware window-overflow for every occupied pane: each
|
||||
// overflow saves the four registers in that pane to the stack frame
|
||||
// pointed to by the pane's a1 (sp). After all panes are flushed, a
|
||||
// scan from the current sp to stackTop covers every live value.
|
||||
// -----------------------------------------------------------------------
|
||||
.section .text.tinygo_scanCurrentStack
|
||||
|
||||
.global tinygo_scanCurrentStack
|
||||
tinygo_scanCurrentStack:
|
||||
entry a1, 48
|
||||
|
||||
// Disable interrupts while flushing register windows.
|
||||
rsr a4, PS
|
||||
s32i a4, a1, 0 // save PS for later restore
|
||||
rsil a4, 3 // XCHAL_EXCM_LEVEL
|
||||
|
||||
// Flush all register windows using recursive call4.
|
||||
// For NAREG=64 (16 panes), 15 recursive levels cover all panes
|
||||
// except the current one (which is kept active).
|
||||
movi a6, 15
|
||||
call4 .Lscan_spill
|
||||
|
||||
// Restore interrupts.
|
||||
l32i a4, a1, 0
|
||||
wsr.ps a4
|
||||
rsync
|
||||
|
||||
// Pass current sp to tinygo_scanstack.
|
||||
// call4 maps caller's a5→callee's a1 (stack ptr for callee's entry)
|
||||
// and caller's a6→callee's a2 (first argument = sp).
|
||||
mov a5, a1 // callee's a1 = valid stack pointer
|
||||
mov a6, a1 // callee's a2 = sp argument
|
||||
call4 tinygo_scanstack
|
||||
|
||||
retw
|
||||
|
||||
.balign 4
|
||||
.Lscan_spill:
|
||||
entry a1, 16
|
||||
beqz a2, .Lscan_spill_done
|
||||
addi a2, a2, -1
|
||||
mov a6, a2
|
||||
call4 .Lscan_spill
|
||||
.Lscan_spill_done:
|
||||
retw
|
||||
@@ -75,6 +75,10 @@ handleInterruptASM:
|
||||
SFREG f30,(30 + 16)*REGSIZE(sp)
|
||||
SFREG f31,(31 + 16)*REGSIZE(sp)
|
||||
#endif
|
||||
// Save ra to a global so handleException can print the caller of the NULL
|
||||
// function pointer.
|
||||
la t0, tinygo_saved_ra
|
||||
SREG ra, 0(t0)
|
||||
call handleInterrupt
|
||||
#ifdef __riscv_flen
|
||||
LFREG f0, (31 + 16)*REGSIZE(sp)
|
||||
@@ -128,3 +132,10 @@ handleInterruptASM:
|
||||
LREG ra, 0*REGSIZE(sp)
|
||||
addi sp, sp, NREG*REGSIZE
|
||||
mret
|
||||
|
||||
.section .bss.tinygo_saved_ra
|
||||
.global tinygo_saved_ra
|
||||
.type tinygo_saved_ra,@object
|
||||
.align 2
|
||||
tinygo_saved_ra:
|
||||
.space REGSIZE
|
||||
|
||||
+2
-12
@@ -5,25 +5,15 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// This example assumes that an analog sensor such as a rotary dial is connected to pin ADC0.
|
||||
// When the dial is turned past the midway point, the built-in LED will light up.
|
||||
|
||||
func main() {
|
||||
machine.InitADC()
|
||||
|
||||
led := machine.LED
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
sensor := machine.ADC{machine.ADC2}
|
||||
sensor.Configure(machine.ADCConfig{})
|
||||
|
||||
for {
|
||||
val := sensor.Get()
|
||||
if val < 0x8000 {
|
||||
led.Low()
|
||||
} else {
|
||||
led.High()
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
println(val)
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build arduino
|
||||
//go:build arduino_uno
|
||||
|
||||
package main
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
//go:build xiao_esp32s3
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
button = machine.D1
|
||||
buttonMode = machine.PinInputPullup
|
||||
buttonPinChange = machine.PinFalling
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
//go:build arduino_uno_q
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
var (
|
||||
pwm = &machine.TIM3
|
||||
pinA = machine.D3 // PB0 = TIM3_CH3
|
||||
pinB = machine.D6 // PB1 = TIM3_CH4
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build arduino
|
||||
//go:build arduino_uno
|
||||
|
||||
package main
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
//go:build digispark
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
var (
|
||||
// Use Timer1 for PWM (recommended for ATtiny85)
|
||||
pwm = machine.Timer1
|
||||
pinA = machine.P1 // PB1, Timer1 channel A (LED pin)
|
||||
pinB = machine.P4 // PB4, Timer1 channel B
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
//go:build esp32c3_supermini
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
var (
|
||||
pwm = machine.PWM0
|
||||
pinA = machine.GPIO5
|
||||
pinB = machine.GPIO6
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
//go:build pico2 || pico_plus2
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
var (
|
||||
pwm = machine.PWM0 // Pin 25 (LED on pico2) corresponds to PWM0.
|
||||
//pinA = machine.LED
|
||||
pinA = machine.GPIO16
|
||||
)
|
||||
@@ -0,0 +1,11 @@
|
||||
//go:build xiao_esp32s3
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
var (
|
||||
pwm = machine.PWM0
|
||||
pinA = machine.D0
|
||||
pinB = machine.D1
|
||||
)
|
||||
@@ -0,0 +1,29 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
time.Sleep(2 * time.Second) // connect via serial
|
||||
buf1 := makeBuffer('|', 600)
|
||||
buf2 := makeBuffer('/', 600)
|
||||
println("start")
|
||||
serialWrite(buf1)
|
||||
serialWrite(buf2)
|
||||
}
|
||||
|
||||
func makeBuffer(sep byte, size int) []byte {
|
||||
buf := make([]byte, size)
|
||||
for i := 0; i < size-5; i += 5 {
|
||||
buf[i] = sep
|
||||
strconv.AppendInt(buf[i+1:i+1:i+5], int64(i), 10)
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func serialWrite(b []byte) {
|
||||
machine.Serial.Write(b)
|
||||
}
|
||||
@@ -15,3 +15,35 @@ func Escape[T any](x T) T {
|
||||
// as-is.
|
||||
panic("internal/abi.Escape: unreachable (implemented in the compiler)")
|
||||
}
|
||||
|
||||
// EscapeNonString forces v to be on the heap, if v contains a
|
||||
// non-string pointer.
|
||||
//
|
||||
// This is used in hash/maphash.Comparable. We cannot hash pointers
|
||||
// to local variables on stack, as their addresses might change on
|
||||
// stack growth. Strings are okay as the hash depends on only the
|
||||
// content, not the pointer.
|
||||
//
|
||||
// This is essentially
|
||||
//
|
||||
// if hasNonStringPointers(T) { Escape(v) }
|
||||
//
|
||||
// Implemented as a compiler intrinsic.
|
||||
func EscapeNonString[T any](v T) { panic("intrinsic") }
|
||||
|
||||
// EscapeToResultNonString models a data flow edge from v to the result,
|
||||
// if v contains a non-string pointer. If v contains only string pointers,
|
||||
// it returns a copy of v, but is not modeled as a data flow edge
|
||||
// from the escape analysis's perspective.
|
||||
//
|
||||
// This is used in unique.clone, to model the data flow edge on the
|
||||
// value with strings excluded, because strings are cloned (by
|
||||
// content).
|
||||
//
|
||||
// TODO: probably we should define this as a intrinsic and EscapeNonString
|
||||
// could just be "heap = EscapeToResultNonString(v)". This way we can model
|
||||
// an edge to the result but not necessarily heap.
|
||||
func EscapeToResultNonString[T any](v T) T {
|
||||
EscapeNonString(v)
|
||||
return *(*T)(NoEscape(unsafe.Pointer(&v)))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Simple conversions to avoid depending on strconv.
|
||||
|
||||
package itoa
|
||||
|
||||
// Itoa converts val to a decimal string.
|
||||
func Itoa(val int) string {
|
||||
if val < 0 {
|
||||
return "-" + Uitoa(uint(-val))
|
||||
}
|
||||
return Uitoa(uint(val))
|
||||
}
|
||||
|
||||
// Uitoa converts val to a decimal string.
|
||||
func Uitoa(val uint) string {
|
||||
if val == 0 { // avoid string allocation
|
||||
return "0"
|
||||
}
|
||||
var buf [20]byte // big enough for 64bit value base 10
|
||||
i := len(buf) - 1
|
||||
for val >= 10 {
|
||||
q := val / 10
|
||||
buf[i] = byte('0' + val - q*10)
|
||||
i--
|
||||
val = q
|
||||
}
|
||||
// val < 10
|
||||
buf[i] = byte('0' + val)
|
||||
return string(buf[i:])
|
||||
}
|
||||
|
||||
const hex = "0123456789abcdef"
|
||||
|
||||
// Uitox converts val (a uint) to a hexadecimal string.
|
||||
func Uitox(val uint) string {
|
||||
if val == 0 { // avoid string allocation
|
||||
return "0x0"
|
||||
}
|
||||
var buf [20]byte // big enough for 64bit value base 16 + 0x
|
||||
i := len(buf) - 1
|
||||
for val >= 16 {
|
||||
q := val / 16
|
||||
buf[i] = hex[val%16]
|
||||
i--
|
||||
val = q
|
||||
}
|
||||
// val < 16
|
||||
buf[i] = hex[val%16]
|
||||
i--
|
||||
buf[i] = 'x'
|
||||
i--
|
||||
buf[i] = '0'
|
||||
return string(buf[i:])
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package itoa_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"internal/itoa"
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
minInt64 int64 = math.MinInt64
|
||||
maxInt64 int64 = math.MaxInt64
|
||||
maxUint64 uint64 = math.MaxUint64
|
||||
)
|
||||
|
||||
func TestItoa(t *testing.T) {
|
||||
tests := []int{int(minInt64), math.MinInt32, -999, -100, -1, 0, 1, 100, 999, math.MaxInt32, int(maxInt64)}
|
||||
for _, tt := range tests {
|
||||
got := itoa.Itoa(tt)
|
||||
want := fmt.Sprint(tt)
|
||||
if want != got {
|
||||
t.Fatalf("Itoa(%d) = %s, want %s", tt, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUitoa(t *testing.T) {
|
||||
tests := []uint{0, 1, 100, 999, math.MaxUint32, uint(maxUint64)}
|
||||
for _, tt := range tests {
|
||||
got := itoa.Uitoa(tt)
|
||||
want := fmt.Sprint(tt)
|
||||
if want != got {
|
||||
t.Fatalf("Uitoa(%d) = %s, want %s", tt, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestUitox(t *testing.T) {
|
||||
tests := []uint{0, 1, 15, 100, 999, math.MaxUint32, uint(maxUint64)}
|
||||
for _, tt := range tests {
|
||||
got := itoa.Uitox(tt)
|
||||
want := fmt.Sprintf("%#x", tt)
|
||||
if want != got {
|
||||
t.Fatalf("Uitox(%x) = %s, want %s", tt, got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,6 +157,10 @@ const (
|
||||
flagIsBinary = 128 // flag that is set if this type uses the hashmap binary algorithm
|
||||
)
|
||||
|
||||
// Flag in the numMethod field (uint16) of Pointer and Struct type descriptors,
|
||||
// indicating that an inline method set is present in the type descriptor.
|
||||
const numMethodHasMethodSet = 0x8000
|
||||
|
||||
// The base type struct. All type structs start with this.
|
||||
type RawType struct {
|
||||
meta uint8 // metadata byte, contains kind and flags (see constants above)
|
||||
@@ -171,16 +175,22 @@ type elemType struct {
|
||||
elem *RawType
|
||||
}
|
||||
|
||||
// ptrType is the type descriptor for pointer types.
|
||||
// The numMethod field stores the number of exported methods in the lower bits,
|
||||
// with bit 15 (numMethodHasMethodSet) indicating whether the methods field is
|
||||
// present. When the flag is clear, the methods field does not exist in the
|
||||
// actual type descriptor and must not be accessed.
|
||||
type ptrType struct {
|
||||
RawType
|
||||
numMethod uint16
|
||||
elem *RawType
|
||||
methods methodSet // only present when numMethod & numMethodHasMethodSet != 0
|
||||
}
|
||||
|
||||
type interfaceType struct {
|
||||
RawType
|
||||
ptrTo *RawType
|
||||
// TODO: methods
|
||||
ptrTo *RawType
|
||||
methods methodSet
|
||||
}
|
||||
|
||||
type arrayType struct {
|
||||
@@ -200,13 +210,19 @@ type mapType struct {
|
||||
key *RawType
|
||||
}
|
||||
|
||||
// namedType is the type descriptor for named types. The numMethod field uses
|
||||
// bit 15 (numMethodHasMethodSet) to indicate whether an inline method set is
|
||||
// present after pkg. When the flag is set, a methodSet follows at
|
||||
// unsafe.Sizeof(namedType{}), and the name string follows after the method
|
||||
// set's entries. When clear, the name string starts directly at that offset.
|
||||
type namedType struct {
|
||||
RawType
|
||||
numMethod uint16
|
||||
ptrTo *RawType
|
||||
elem *RawType
|
||||
pkg *byte
|
||||
name [1]byte
|
||||
// if numMethod & numMethodHasMethodSet != 0: methodSet follows here
|
||||
// name (null-terminated "pkg.Name\0") follows after the method set (or directly here)
|
||||
}
|
||||
|
||||
// Type for struct types. The numField value is intentionally put before ptrTo
|
||||
@@ -216,6 +232,10 @@ type namedType struct {
|
||||
// The fields array isn't necessarily 1 structField long, instead it is as long
|
||||
// as numFields. The array is given a length of 1 to satisfy the Go type
|
||||
// checker.
|
||||
// The numMethod field stores the number of exported methods in the lower bits,
|
||||
// with bit 15 (numMethodHasMethodSet) indicating whether an inline method set
|
||||
// follows the fields array. When the flag is clear, no method set is present
|
||||
// and the type descriptor ends after the last structField entry.
|
||||
type structType struct {
|
||||
RawType
|
||||
numMethod uint16
|
||||
@@ -224,6 +244,7 @@ type structType struct {
|
||||
size uint32
|
||||
numField uint16
|
||||
fields [1]structField // the remaining fields are all of type structField
|
||||
// methods methodSet follows after fields, only when numMethod & numMethodHasMethodSet != 0
|
||||
}
|
||||
|
||||
type structField struct {
|
||||
@@ -231,6 +252,12 @@ type structField struct {
|
||||
data unsafe.Pointer // various bits of information, packed in a byte array
|
||||
}
|
||||
|
||||
// Method set, as emitted by the compiler.
|
||||
type methodSet struct {
|
||||
length uintptr
|
||||
methods [0]unsafe.Pointer // variable number of method signature pointers
|
||||
}
|
||||
|
||||
// Equivalent to (go/types.Type).Underlying(): if this is a named type return
|
||||
// the underlying type, else just return the type itself.
|
||||
func (t *RawType) underlying() *RawType {
|
||||
@@ -733,21 +760,38 @@ func (t *RawType) FieldAlign() int {
|
||||
// AssignableTo returns whether a value of type t can be assigned to a variable
|
||||
// of type u.
|
||||
func (t *RawType) AssignableTo(u Type) bool {
|
||||
if t == u.(*RawType) {
|
||||
return true
|
||||
}
|
||||
|
||||
if t.underlying() == u.(*RawType).underlying() && (!t.isNamed() || !u.(*RawType).isNamed()) {
|
||||
return true
|
||||
}
|
||||
|
||||
if u.Kind() == Interface && u.NumMethod() == 0 {
|
||||
u_raw := u.(*RawType)
|
||||
if t == u_raw {
|
||||
return true
|
||||
}
|
||||
|
||||
if u.Kind() == Interface {
|
||||
panic("reflect: unimplemented: AssignableTo with interface")
|
||||
// T is an interface type and x implements T.
|
||||
u_itf := (*interfaceType)(unsafe.Pointer(u_raw.underlying()))
|
||||
return typeImplementsMethodSet(unsafe.Pointer(t), unsafe.Pointer(&u_itf.methods))
|
||||
}
|
||||
|
||||
t_named := t.isNamed()
|
||||
u_named := u_raw.isNamed()
|
||||
if t_named && u_named {
|
||||
return false
|
||||
}
|
||||
if t.underlying() == u_raw.underlying() {
|
||||
return true
|
||||
}
|
||||
|
||||
if t.Kind() == Chan && u_raw.Kind() == Chan {
|
||||
t_chan := (*elemType)(unsafe.Pointer(t.underlying()))
|
||||
u_chan := (*elemType)(unsafe.Pointer(u_raw.underlying()))
|
||||
if t_chan.elem != u_chan.elem {
|
||||
return false
|
||||
}
|
||||
if t_chan.ChanDir() != BothDir {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -755,7 +799,85 @@ func (t *RawType) Implements(u Type) bool {
|
||||
if u.Kind() != Interface {
|
||||
panic("reflect: non-interface type passed to Type.Implements")
|
||||
}
|
||||
return t.AssignableTo(u)
|
||||
u_itf := (*interfaceType)(unsafe.Pointer(u.(*RawType).underlying()))
|
||||
return typeImplementsMethodSet(unsafe.Pointer(t), unsafe.Pointer(&u_itf.methods))
|
||||
}
|
||||
|
||||
// typeImplementsMethodSet checks whether the concrete type (identified by its
|
||||
// typecode pointer) implements the given method set. Both the concrete type's
|
||||
// method set and the asserted method set are sorted arrays of method signature
|
||||
// pointers, so comparison is O(n+m).
|
||||
//
|
||||
//go:linkname typeImplementsMethodSet runtime.typeImplementsMethodSet
|
||||
func typeImplementsMethodSet(concreteType, assertedMethodSet unsafe.Pointer) bool {
|
||||
if concreteType == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
const ptrSize = unsafe.Sizeof((*byte)(nil))
|
||||
itfNumMethod := *(*uintptr)(assertedMethodSet)
|
||||
if itfNumMethod == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
// Pull the method set out of the concrete type.
|
||||
var methods *methodSet
|
||||
metaByte := *(*uint8)(concreteType)
|
||||
if metaByte&flagNamed != 0 {
|
||||
ct := (*namedType)(concreteType)
|
||||
if ct.numMethod&numMethodHasMethodSet == 0 {
|
||||
return false
|
||||
}
|
||||
methods = (*methodSet)(unsafe.Add(unsafe.Pointer(ct), unsafe.Sizeof(*ct)))
|
||||
} else if metaByte&kindMask == uint8(Interface) {
|
||||
ct := (*interfaceType)(concreteType)
|
||||
methods = &ct.methods
|
||||
} else if metaByte&kindMask == uint8(Pointer) {
|
||||
ct := (*ptrType)(concreteType)
|
||||
if ct.numMethod&numMethodHasMethodSet == 0 {
|
||||
return false
|
||||
}
|
||||
methods = &ct.methods
|
||||
} else if metaByte&kindMask == uint8(Struct) {
|
||||
ct := (*structType)(concreteType)
|
||||
if ct.numMethod&numMethodHasMethodSet == 0 {
|
||||
return false
|
||||
}
|
||||
// For struct types, the method set follows after the variable-length
|
||||
// fields array. We need to compute its offset dynamically.
|
||||
fieldSize := unsafe.Sizeof(structField{})
|
||||
methodsPtr := unsafe.Add(unsafe.Pointer(&ct.fields[0]), uintptr(ct.numField)*fieldSize)
|
||||
methods = (*methodSet)(methodsPtr)
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
|
||||
concreteTypePtr := unsafe.Pointer(&methods.methods)
|
||||
concreteTypeEnd := unsafe.Add(concreteTypePtr, uintptr(methods.length)*ptrSize)
|
||||
|
||||
// Iterate over each method in the interface method set, and check whether
|
||||
// the method exists in the method set of the concrete type.
|
||||
// Both method sets are sorted, so we can use a linear scan.
|
||||
assertedTypePtr := unsafe.Add(assertedMethodSet, ptrSize)
|
||||
assertedTypeEnd := unsafe.Add(assertedTypePtr, itfNumMethod*ptrSize)
|
||||
for assertedTypePtr != assertedTypeEnd {
|
||||
assertedMethod := *(*unsafe.Pointer)(assertedTypePtr)
|
||||
|
||||
for {
|
||||
if concreteTypePtr == concreteTypeEnd {
|
||||
return false
|
||||
}
|
||||
concreteMethod := *(*unsafe.Pointer)(concreteTypePtr)
|
||||
concreteTypePtr = unsafe.Add(concreteTypePtr, ptrSize)
|
||||
if concreteMethod == assertedMethod {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assertedTypePtr = unsafe.Add(assertedTypePtr, ptrSize)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Comparable returns whether values of this type can be compared to each other.
|
||||
@@ -782,14 +904,14 @@ func (t *RawType) ChanDir() ChanDir {
|
||||
func (t *RawType) NumMethod() int {
|
||||
|
||||
if t.isNamed() {
|
||||
return int((*namedType)(unsafe.Pointer(t)).numMethod)
|
||||
return int((*namedType)(unsafe.Pointer(t)).numMethod & ^uint16(numMethodHasMethodSet))
|
||||
}
|
||||
|
||||
switch t.Kind() {
|
||||
case Pointer:
|
||||
return int((*ptrType)(unsafe.Pointer(t)).numMethod)
|
||||
return int((*ptrType)(unsafe.Pointer(t)).numMethod & ^uint16(numMethodHasMethodSet))
|
||||
case Struct:
|
||||
return int((*structType)(unsafe.Pointer(t)).numMethod)
|
||||
return int((*structType)(unsafe.Pointer(t)).numMethod & ^uint16(numMethodHasMethodSet))
|
||||
case Interface:
|
||||
//FIXME: Use len(methods)
|
||||
return (*interfaceType)(unsafe.Pointer(t)).ptrTo.NumMethod()
|
||||
@@ -816,7 +938,14 @@ func readStringZ(data unsafe.Pointer) string {
|
||||
|
||||
func (t *RawType) name() string {
|
||||
ntype := (*namedType)(unsafe.Pointer(t))
|
||||
return readStringZ(unsafe.Pointer(&ntype.name[0]))
|
||||
// The name follows after the fixed fields (and optionally the method set).
|
||||
ptr := unsafe.Add(unsafe.Pointer(ntype), unsafe.Sizeof(*ntype))
|
||||
if ntype.numMethod&numMethodHasMethodSet != 0 {
|
||||
ms := (*methodSet)(ptr)
|
||||
// Skip past the length field and the method pointer entries.
|
||||
ptr = unsafe.Add(ptr, unsafe.Sizeof(uintptr(0))+uintptr(ms.length)*unsafe.Sizeof(unsafe.Pointer(nil)))
|
||||
}
|
||||
return readStringZ(ptr)
|
||||
}
|
||||
|
||||
func (t *RawType) Name() string {
|
||||
|
||||
@@ -138,7 +138,7 @@ func TypeAssert[T any](v Value) (T, bool) {
|
||||
var zero T
|
||||
return zero, false
|
||||
}
|
||||
if !v.isIndirect() {
|
||||
if !v.isIndirect() && v.typecode.Size() <= unsafe.Sizeof(uintptr(0)) {
|
||||
return *(*T)(unsafe.Pointer(&v.value)), true
|
||||
}
|
||||
return *(*T)(v.value), true
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
//go:build !tinygo.wasm
|
||||
|
||||
package unix
|
||||
|
||||
import "syscall"
|
||||
|
||||
type GetRandomFlag uintptr
|
||||
|
||||
const (
|
||||
@@ -8,5 +12,7 @@ const (
|
||||
)
|
||||
|
||||
func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) {
|
||||
panic("todo: unix.GetRandom")
|
||||
// Not supported on most TinyGo targets.
|
||||
// On real Linux the sysrand package will fall back to /dev/urandom.
|
||||
return 0, syscall.ENOSYS
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
//go:build tinygo.wasm
|
||||
|
||||
package unix
|
||||
|
||||
import "unsafe"
|
||||
|
||||
type GetRandomFlag uintptr
|
||||
|
||||
const (
|
||||
GRND_NONBLOCK GetRandomFlag = 0x0001
|
||||
GRND_RANDOM GetRandomFlag = 0x0002
|
||||
)
|
||||
|
||||
func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) {
|
||||
if len(p) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
libc_arc4random_buf(unsafe.Pointer(&p[0]), uint(len(p)))
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// void arc4random_buf(void *buf, size_t buflen);
|
||||
//
|
||||
//export arc4random_buf
|
||||
func libc_arc4random_buf(buf unsafe.Pointer, buflen uint)
|
||||
@@ -22,7 +22,8 @@ type Task struct {
|
||||
state state
|
||||
|
||||
// This is needed for some crypto packages.
|
||||
FipsIndicator uint8
|
||||
FipsIndicator uint8
|
||||
FipsOnlyBypass bool
|
||||
|
||||
// State of the goroutine: running, paused, or must-resume-next-pause.
|
||||
// This extra field doesn't increase memory usage on 32-bit CPUs and above,
|
||||
|
||||
@@ -46,26 +46,40 @@ tinygo_swapTask:
|
||||
// arbitrary register while registers are flushed.
|
||||
rsil a4, 3 // XCHAL_EXCM_LEVEL
|
||||
|
||||
// Flush all unsaved registers to the stack.
|
||||
// This trick has been borrowed from the Zephyr project:
|
||||
// https://github.com/zephyrproject-rtos/zephyr/blob/d79b003758/arch/xtensa/include/xtensa-asm2-s.h#L17
|
||||
and a12, a12, a12
|
||||
rotw 3
|
||||
and a12, a12, a12
|
||||
rotw 3
|
||||
and a12, a12, a12
|
||||
rotw 3
|
||||
and a12, a12, a12
|
||||
rotw 3
|
||||
and a12, a12, a12
|
||||
rotw 4
|
||||
// Save the old PS (in a4) to the stack because call4 clobbers a4-a7.
|
||||
s32i a4, sp, 4
|
||||
|
||||
// Flush all register windows to the stack using recursive call4.
|
||||
//
|
||||
// The previous ROTW-based approach (borrowed from Zephyr) does NOT
|
||||
// actually trigger window overflow exceptions on Xtensa LX7 — ROTW
|
||||
// simply modifies WindowBase without saving any registers to the stack.
|
||||
// This leaves stale window data in the physical register file after a
|
||||
// goroutine switch, corrupting the overflow save chain when the new
|
||||
// goroutine's deeper calls trigger overflow of old goroutine windows.
|
||||
//
|
||||
// Instead, we recursively call a small function via call4. Each call4 +
|
||||
// entry triggers the hardware window-overflow mechanism for any occupied
|
||||
// pane being reused, correctly saving registers to the stack.
|
||||
// For NAREG=64 (16 panes), 15 recursive levels cover all panes except
|
||||
// the current one (tinygo_swapTask), which must stay active.
|
||||
movi a6, 15
|
||||
call4 .Lspill_windows
|
||||
|
||||
// After the recursive spill returns, the physical register file still
|
||||
// has WindowStart bits set for the spill helper frames.
|
||||
// We will clear WindowStart completely (to 0) right before the retw.n
|
||||
// below, after the stack switch is done. This prevents stale overflow
|
||||
// when the new goroutine's calls rotate back into these panes.
|
||||
|
||||
// Restore interrupts.
|
||||
l32i a4, sp, 4 // reload saved PS
|
||||
wsr.ps a4
|
||||
rsync
|
||||
|
||||
// At this point, the following is true:
|
||||
// WindowStart == 1 << WindowBase
|
||||
// Therefore, we don't need to do this manually.
|
||||
// All other windows have been properly flushed to their stacks.
|
||||
// It also means that the stack pointer can now be safely modified.
|
||||
|
||||
// Save a0, which stores the return address and the parent register window
|
||||
@@ -83,6 +97,30 @@ tinygo_swapTask:
|
||||
// register also stores the parent register window.
|
||||
l32i.n a0, sp, 0
|
||||
|
||||
// Clear ALL WindowStart bits. With all windows spilled to the stack,
|
||||
// we must ensure no stale WS bits remain: the retw.n below will trigger
|
||||
// underflow4 to load the new goroutine's registers from the new stack
|
||||
// (which sets the appropriate WS bit via rfwu). Any stale WS bits
|
||||
// (from spill helpers or the old goroutine) would cause spurious
|
||||
// overflows of garbage register values into memory.
|
||||
movi a5, 0
|
||||
wsr a5, WINDOWSTART
|
||||
rsync
|
||||
|
||||
// Return into the new stack. This instruction will trigger a window
|
||||
// underflow, reloading the saved registers from the stack.
|
||||
retw.n
|
||||
|
||||
// Recursive helper for flushing all register windows.
|
||||
// Parameter: a2 = remaining recursion depth (passed via caller's a6).
|
||||
// Each call4 + entry triggers the hardware overflow mechanism for any
|
||||
// occupied pane at the new WindowBase position.
|
||||
.balign 4
|
||||
.Lspill_windows:
|
||||
entry a1, 16
|
||||
beqz a2, .Lspill_done
|
||||
addi a2, a2, -1
|
||||
mov a6, a2
|
||||
call4 .Lspill_windows
|
||||
.Lspill_done:
|
||||
retw.n
|
||||
|
||||
@@ -74,3 +74,8 @@ func (s *state) pause() {
|
||||
func SystemStack() uintptr {
|
||||
return systemStack
|
||||
}
|
||||
|
||||
//export tinygo_task_current
|
||||
func tinygo_task_current() unsafe.Pointer {
|
||||
return unsafe.Pointer(Current())
|
||||
}
|
||||
|
||||
@@ -71,3 +71,8 @@ func (s *state) pause() {
|
||||
func SystemStack() uintptr {
|
||||
return *runtime_systemStackPtr()
|
||||
}
|
||||
|
||||
//export tinygo_task_current
|
||||
func tinygo_task_current() unsafe.Pointer {
|
||||
return unsafe.Pointer(Current())
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build arduino
|
||||
//go:build arduino_uno
|
||||
|
||||
package machine
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
//go:build arduino_uno_q
|
||||
|
||||
// Arduino UNO Q board with STM32U585 processor.
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/stm32"
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Arduino Pins
|
||||
A0 = PA4
|
||||
A1 = PA5
|
||||
A2 = PA6
|
||||
A3 = PA7
|
||||
A4 = PC1
|
||||
A5 = PC0
|
||||
|
||||
// ADC pin aliases
|
||||
ADC0 = A0
|
||||
ADC1 = A1
|
||||
ADC2 = A2
|
||||
ADC3 = A3
|
||||
ADC4 = A4
|
||||
ADC5 = A5
|
||||
|
||||
D0 = PB7 // USART1 RX, PWM TIM4_CH2
|
||||
D1 = PB6 // USART1 TX, PWM TIM4_CH1
|
||||
D2 = PB3 // PWM TIM2_CH2
|
||||
D3 = PB0 // PWM TIM3_CH3
|
||||
D4 = PA12
|
||||
D5 = PA11 // PWM TIM1_CH4
|
||||
D6 = PB1 // PWM TIM3_CH4
|
||||
D7 = PB2
|
||||
D8 = PB4 // PWM TIM3_CH1
|
||||
D9 = PB8 // PWM TIM4_CH3 / TIM16_CH1
|
||||
D10 = PB9 // PWM TIM4_CH4 / TIM17_CH1
|
||||
D11 = PB15 // PWM TIM15_CH2
|
||||
D12 = PB14 // PWM TIM15_CH1
|
||||
D13 = PB13
|
||||
D18 = PC1
|
||||
D19 = PC0
|
||||
D20 = PB10 // I2C2 SCL, PWM TIM2_CH3
|
||||
D21 = PB11 // I2C2 SDA, PWM TIM2_CH4
|
||||
)
|
||||
|
||||
const (
|
||||
LED = LED3_R
|
||||
LED3_R = PH10
|
||||
LED3_G = PH11
|
||||
LED3_B = PH12
|
||||
LED4_R = PH13
|
||||
LED4_G = PH14
|
||||
LED4_B = PH15
|
||||
)
|
||||
|
||||
const (
|
||||
// Default UART pins (LPUART1 active via ST-LINK virtual COM port)
|
||||
UART_TX_PIN = PG7
|
||||
UART_RX_PIN = PG8
|
||||
|
||||
// USART1 pins (Arduino header D1/D0)
|
||||
UART1_TX_PIN = D1
|
||||
UART1_RX_PIN = D0
|
||||
|
||||
// LPUART1 pins (active via ST-LINK virtual COM port)
|
||||
UART2_TX_PIN = PG7
|
||||
UART2_RX_PIN = PG8
|
||||
|
||||
// I2C pins, also connected to I2C2
|
||||
I2C0_SCL_PIN = D20
|
||||
I2C0_SDA_PIN = D21
|
||||
// QWIIC connector pins, also connected to I2C4
|
||||
I2C1_SCL_PIN = PD12
|
||||
I2C1_SDA_PIN = PD13
|
||||
|
||||
// SPI pins
|
||||
SPI1_SCK_PIN = PA5
|
||||
SPI1_SDI_PIN = PA6
|
||||
SPI1_SDO_PIN = PA7
|
||||
SPI0_SCK_PIN = SPI1_SCK_PIN
|
||||
SPI0_SDI_PIN = SPI1_SDI_PIN
|
||||
SPI0_SDO_PIN = SPI1_SDO_PIN
|
||||
)
|
||||
|
||||
var (
|
||||
// USART1 on PB6/PB7 (Arduino header D1/D0).
|
||||
UART1 = &_UART1
|
||||
_UART1 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART1,
|
||||
TxAltFuncSelector: AF7_USART1_2_3,
|
||||
RxAltFuncSelector: AF7_USART1_2_3,
|
||||
}
|
||||
|
||||
// LPUART1 on PG7/PG8 (active via ST-LINK virtual COM port).
|
||||
UART2 = &_UART2
|
||||
_UART2 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: (*stm32.USART_Type)(unsafe.Pointer(stm32.LPUART1)),
|
||||
TxAltFuncSelector: AF8_UART4_5_LPUART1_SDMMC1,
|
||||
RxAltFuncSelector: AF8_UART4_5_LPUART1_SDMMC1,
|
||||
}
|
||||
DefaultUART = UART2
|
||||
|
||||
// I2C2 is documented, alias to I2C0 as well
|
||||
I2C2 = &I2C{
|
||||
Bus: stm32.I2C2,
|
||||
AltFuncSelector: AF4_I2C1_2_3_4,
|
||||
}
|
||||
I2C0 = I2C2
|
||||
|
||||
// I2C4 is is connected to the QWIIC connector, alias to I2C1 as well
|
||||
I2C4 = &I2C{
|
||||
Bus: stm32.I2C4,
|
||||
AltFuncSelector: AF4_I2C1_2_3_4,
|
||||
}
|
||||
I2C1 = I2C4
|
||||
|
||||
// SPI1 is documented, alias to SPI0 as well
|
||||
SPI1 = &SPI{
|
||||
Bus: stm32.SPI1,
|
||||
AltFuncSelector: AF5_SPI1_2_3_OCTOSPI1_OCTOSPI2,
|
||||
}
|
||||
SPI0 = SPI1
|
||||
)
|
||||
|
||||
func init() {
|
||||
UART1.Interrupt = interrupt.New(stm32.IRQ_USART1, _UART1.handleInterrupt)
|
||||
UART2.Interrupt = interrupt.New(stm32.IRQ_LPUART1, _UART2.handleInterrupt)
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build (avr && atmega328p) || arduino || arduino_nano
|
||||
//go:build (avr && atmega328p) || arduino_uno || arduino_nano
|
||||
|
||||
package machine
|
||||
|
||||
|
||||
@@ -2,17 +2,26 @@
|
||||
|
||||
package machine
|
||||
|
||||
// Digispark is a tiny ATtiny85-based board with 6 I/O pins.
|
||||
//
|
||||
// PWM is available on the following pins:
|
||||
// - P0 (PB0): Timer0 channel A
|
||||
// - P1 (PB1): Timer0 channel B or Timer1 channel A (LED pin)
|
||||
// - P4 (PB4): Timer1 channel B
|
||||
//
|
||||
// Timer1 is recommended for PWM as it provides more flexible frequency control.
|
||||
|
||||
// Return the current CPU frequency in hertz.
|
||||
func CPUFrequency() uint32 {
|
||||
return 16000000
|
||||
}
|
||||
|
||||
const (
|
||||
P0 Pin = PB0
|
||||
P1 Pin = PB1
|
||||
P0 Pin = PB0 // PWM available (Timer0 OC0A)
|
||||
P1 Pin = PB1 // PWM available (Timer0 OC0B or Timer1 OC1A)
|
||||
P2 Pin = PB2
|
||||
P3 Pin = PB3
|
||||
P4 Pin = PB4
|
||||
P4 Pin = PB4 // PWM available (Timer1 OC1B)
|
||||
P5 Pin = PB5
|
||||
|
||||
LED = P1
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
//go:build esp32_generic
|
||||
|
||||
package machine
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
SDA_PIN = NoPin
|
||||
SCL_PIN = NoPin
|
||||
)
|
||||
@@ -30,9 +30,6 @@ const (
|
||||
|
||||
// ADC pins
|
||||
const (
|
||||
ADC0 Pin = ADC1_0
|
||||
ADC1 Pin = ADC2_0
|
||||
|
||||
ADC1_0 Pin = IO0
|
||||
ADC1_1 Pin = IO1
|
||||
ADC1_2 Pin = IO2
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
//go:build esp32c3_generic
|
||||
|
||||
package machine
|
||||
|
||||
const (
|
||||
SDA_PIN = NoPin
|
||||
SCL_PIN = NoPin
|
||||
)
|
||||
@@ -1,6 +1,6 @@
|
||||
//go:build esp32c3_supermini
|
||||
|
||||
// This file contains the pin mappings for the ESP32 supermini boards.
|
||||
// This file contains the pin mappings for the ESP32C3 supermini board.
|
||||
//
|
||||
// - https://web.archive.org/web/20240805232453/https://dl.artronshop.co.th/ESP32-C3%20SuperMini%20datasheet.pdf
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
//go:build esp32s3_generic
|
||||
|
||||
package machine
|
||||
|
||||
const (
|
||||
SCL_PIN = NoPin
|
||||
SDA_PIN = NoPin
|
||||
|
||||
SPI1_SCK_PIN = NoPin // SCK
|
||||
SPI1_MOSI_PIN = NoPin // SDO (MOSI)
|
||||
SPI1_MISO_PIN = NoPin // SDI (MISO)
|
||||
SPI1_CS_PIN = NoPin // CS
|
||||
|
||||
SPI2_SCK_PIN = NoPin // SCK
|
||||
SPI2_MOSI_PIN = NoPin // SDO (MOSI)
|
||||
SPI2_MISO_PIN = NoPin // SDI (MISO)
|
||||
SPI2_CS_PIN = NoPin // CS
|
||||
)
|
||||
@@ -0,0 +1,88 @@
|
||||
//go:build esp32s3_supermini
|
||||
|
||||
// This file contains the pin mappings for the ESP32S3 supermini board.
|
||||
//
|
||||
// - https://www.nologo.tech/product/esp32/esp32s3/esp32s3supermini/esp32S3SuperMini.html
|
||||
|
||||
package machine
|
||||
|
||||
// Digital Pins
|
||||
const (
|
||||
IO1 = GPIO1
|
||||
IO2 = GPIO2
|
||||
IO3 = GPIO3
|
||||
IO4 = GPIO4
|
||||
IO5 = GPIO5
|
||||
IO6 = GPIO6
|
||||
IO7 = GPIO7
|
||||
IO8 = GPIO8
|
||||
IO9 = GPIO9
|
||||
IO10 = GPIO10
|
||||
IO11 = GPIO11
|
||||
IO12 = GPIO12
|
||||
IO13 = GPIO13
|
||||
IO14 = GPIO14
|
||||
IO15 = GPIO15
|
||||
IO16 = GPIO16
|
||||
IO17 = GPIO17
|
||||
IO18 = GPIO18
|
||||
IO21 = GPIO21
|
||||
IO33 = GPIO33
|
||||
IO34 = GPIO34
|
||||
IO35 = GPIO35
|
||||
IO36 = GPIO36
|
||||
IO37 = GPIO37
|
||||
IO38 = GPIO38
|
||||
IO39 = GPIO39
|
||||
IO40 = GPIO40
|
||||
IO41 = GPIO41
|
||||
IO42 = GPIO42
|
||||
IO43 = GPIO43
|
||||
IO44 = GPIO44
|
||||
IO45 = GPIO45
|
||||
IO46 = GPIO46
|
||||
IO47 = GPIO47
|
||||
IO48 = GPIO48
|
||||
)
|
||||
|
||||
// Built-in LED
|
||||
const LED = GPIO48
|
||||
|
||||
// Analog pins
|
||||
const (
|
||||
A1 = GPIO1
|
||||
A2 = GPIO2
|
||||
A3 = GPIO3
|
||||
A4 = GPIO4
|
||||
A5 = GPIO5
|
||||
A6 = GPIO6
|
||||
A7 = GPIO7
|
||||
A8 = GPIO8
|
||||
A9 = GPIO9
|
||||
A10 = GPIO10
|
||||
A11 = GPIO11
|
||||
A12 = GPIO12
|
||||
A13 = GPIO13
|
||||
A14 = GPIO14
|
||||
A15 = GPIO15
|
||||
A16 = GPIO16
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
SDA_PIN = GPIO8
|
||||
SCL_PIN = GPIO9
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI1_SCK_PIN = GPIO4
|
||||
SPI1_MISO_PIN = GPIO5
|
||||
SPI1_MOSI_PIN = GPIO6
|
||||
SPI1_CS_PIN = GPIO7
|
||||
|
||||
SPI2_SCK_PIN = NoPin
|
||||
SPI2_MOSI_PIN = NoPin
|
||||
SPI2_MISO_PIN = NoPin
|
||||
SPI2_CS_PIN = NoPin
|
||||
)
|
||||
@@ -43,6 +43,15 @@ const (
|
||||
USBCDC_DP_PIN = PA25
|
||||
)
|
||||
|
||||
// UART0 pins
|
||||
const (
|
||||
UART0_TX_PIN = D1
|
||||
UART0_RX_PIN = D0
|
||||
)
|
||||
|
||||
// UART0 on the Feather M0.
|
||||
var UART0 = &sercomUSART0
|
||||
|
||||
// UART1 pins
|
||||
const (
|
||||
UART_TX_PIN = D10
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
//go:build vicharak_shrike_lite
|
||||
|
||||
// Pin mappings for Vicharak Shrike-Lite.
|
||||
//
|
||||
// Reference: https://vicharak-in.github.io/shrike/shrike_pinouts.html
|
||||
|
||||
package machine
|
||||
|
||||
// Digital
|
||||
const (
|
||||
IO0 Pin = GPIO0
|
||||
IO1 Pin = GPIO1
|
||||
IO2 Pin = GPIO2
|
||||
IO3 Pin = GPIO3
|
||||
IO4 Pin = GPIO4
|
||||
IO5 Pin = GPIO5
|
||||
IO6 Pin = GPIO6
|
||||
IO7 Pin = GPIO7
|
||||
IO8 Pin = GPIO8
|
||||
IO9 Pin = GPIO9
|
||||
IO10 Pin = GPIO10
|
||||
IO11 Pin = GPIO11
|
||||
IO12 Pin = GPIO12
|
||||
IO13 Pin = GPIO13
|
||||
IO14 Pin = GPIO14
|
||||
IO15 Pin = GPIO15
|
||||
IO16 Pin = GPIO16
|
||||
IO17 Pin = GPIO17
|
||||
IO18 Pin = GPIO18
|
||||
IO19 Pin = GPIO19
|
||||
IO20 Pin = GPIO20
|
||||
IO21 Pin = GPIO21
|
||||
IO22 Pin = GPIO22
|
||||
IO23 Pin = GPIO23
|
||||
IO24 Pin = GPIO24
|
||||
IO25 Pin = GPIO25
|
||||
IO26 Pin = GPIO26
|
||||
IO27 Pin = GPIO27
|
||||
IO28 Pin = GPIO28
|
||||
IO29 Pin = GPIO29
|
||||
)
|
||||
|
||||
// FPGA Pins
|
||||
const (
|
||||
FPGA_EN Pin = IO13
|
||||
FPGA_PWR Pin = IO12
|
||||
// SPI_SCLK
|
||||
F3 Pin = IO2
|
||||
// SPI_SS
|
||||
F4 Pin = IO1
|
||||
// SPI_SI (MOSI)
|
||||
F5 Pin = IO3
|
||||
// SPI_SO (MISO) / CONFIG
|
||||
F6 Pin = IO0
|
||||
F18 Pin = IO14
|
||||
F17 Pin = IO15
|
||||
)
|
||||
|
||||
// Analog pins
|
||||
const (
|
||||
A0 Pin = IO26
|
||||
A1 Pin = IO27
|
||||
A2 Pin = IO28
|
||||
A3 Pin = IO29
|
||||
)
|
||||
|
||||
// LED
|
||||
const (
|
||||
LED = IO4
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
I2C0_SDA_PIN Pin = IO24
|
||||
I2C0_SCL_PIN Pin = IO25
|
||||
|
||||
I2C1_SDA_PIN Pin = IO6
|
||||
I2C1_SCL_PIN Pin = IO7
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI0_SCK_PIN Pin = IO18
|
||||
SPI0_SDO_PIN Pin = IO19
|
||||
SPI0_SDI_PIN Pin = IO20
|
||||
|
||||
SPI1_SCK_PIN Pin = IO10
|
||||
SPI1_SDO_PIN Pin = IO11
|
||||
SPI1_SDI_PIN Pin = IO8
|
||||
)
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
const (
|
||||
xoscFreq = 12 // MHz
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = IO28
|
||||
UART0_RX_PIN = IO29
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
UART1_TX_PIN = IO24
|
||||
UART1_RX_PIN = IO25
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
// USB CDC identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "Shrike-Lite"
|
||||
usb_STRING_MANUFACTURER = "Vicharak"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x2e8a
|
||||
usb_PID uint16 = 0x0003
|
||||
)
|
||||
@@ -47,9 +47,15 @@ const (
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI_SCK_PIN = GPIO7
|
||||
SPI_SDI_PIN = GPIO9
|
||||
SPI_SDO_PIN = GPIO8
|
||||
SPI1_SCK_PIN = GPIO7 // D8
|
||||
SPI1_MISO_PIN = GPIO8 // D9
|
||||
SPI1_MOSI_PIN = GPIO9 // D10
|
||||
SPI1_CS_PIN = NoPin
|
||||
|
||||
SPI2_SCK_PIN = NoPin
|
||||
SPI2_MOSI_PIN = NoPin
|
||||
SPI2_MISO_PIN = NoPin
|
||||
SPI2_CS_PIN = NoPin
|
||||
)
|
||||
|
||||
// Onboard LEDs
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
//go:build xiao_rp2350
|
||||
|
||||
// This file contains the pin mappings for the Seeed XIAO RP2350 boards.
|
||||
//
|
||||
// XIAO RP2350 is a microcontroller using the Raspberry Pi RP2350 chip.
|
||||
//
|
||||
// - https://wiki.seeedstudio.com/XIAO-RP2350/
|
||||
package machine
|
||||
|
||||
// Digital Pins
|
||||
const (
|
||||
D0 Pin = GPIO26
|
||||
D1 Pin = GPIO27
|
||||
D2 Pin = GPIO28
|
||||
D3 Pin = GPIO5
|
||||
D4 Pin = GPIO6
|
||||
D5 Pin = GPIO7
|
||||
D6 Pin = GPIO0
|
||||
D7 Pin = GPIO1
|
||||
D8 Pin = GPIO2
|
||||
D9 Pin = GPIO4
|
||||
D10 Pin = GPIO3
|
||||
D11 Pin = GPIO21
|
||||
D12 Pin = GPIO20
|
||||
D13 Pin = GPIO17
|
||||
D14 Pin = GPIO16
|
||||
D15 Pin = GPIO11
|
||||
D16 Pin = GPIO12
|
||||
D17 Pin = GPIO10
|
||||
)
|
||||
|
||||
// Analog pins
|
||||
const (
|
||||
A0 Pin = D0
|
||||
A1 Pin = D1
|
||||
A2 Pin = D2
|
||||
)
|
||||
|
||||
// Onboard LEDs
|
||||
const (
|
||||
NEOPIXEL = GPIO22
|
||||
WS2812 = GPIO22
|
||||
NEO_PWR = GPIO23
|
||||
NEOPIXEL_POWER = GPIO23
|
||||
|
||||
LED = GPIO25
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
I2C0_SDA_PIN Pin = D14
|
||||
I2C0_SCL_PIN Pin = D13
|
||||
|
||||
I2C1_SDA_PIN Pin = D4
|
||||
I2C1_SCL_PIN Pin = D5
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI0_SCK_PIN Pin = D8
|
||||
SPI0_SDO_PIN Pin = D10
|
||||
SPI0_SDI_PIN Pin = D9
|
||||
|
||||
SPI1_SCK_PIN Pin = D17
|
||||
SPI1_SDO_PIN Pin = D15
|
||||
SPI1_SDI_PIN Pin = D16
|
||||
)
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
const (
|
||||
xoscFreq = 12 // MHz
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
// USB CDC identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "XIAO RP2350"
|
||||
usb_STRING_MANUFACTURER = "Seeed"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x2e8a
|
||||
usb_PID uint16 = 0x000a
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build nrf || nrf51 || nrf52 || nrf528xx || stm32f4 || stm32l0 || stm32l4 || stm32wlx || atsamd21 || atsamd51 || atsame5x || rp2040 || rp2350
|
||||
//go:build esp32c3 || nrf || nrf51 || nrf52 || nrf528xx || stm32f4 || stm32l0 || stm32l4 || stm32wlx || atsamd21 || atsamd51 || atsame5x || rp2040 || rp2350
|
||||
|
||||
package machine
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//go:build !baremetal || atmega || nrf || sam || stm32 || fe310 || k210 || rp2040 || rp2350 || mimxrt1062 || (esp32c3 && !m5stamp_c3) || esp32
|
||||
//go:build !baremetal || atmega || nrf || sam || stm32 || fe310 || k210 || rp2040 || rp2350 || mimxrt1062 || (esp32c3 && !m5stamp_c3) || esp32 || esp32s3
|
||||
|
||||
package machine
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !baremetal && (arduino || arduino_nano)
|
||||
//go:build !baremetal && (arduino_uno || arduino_nano)
|
||||
|
||||
package machine
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"device/sam"
|
||||
"errors"
|
||||
"internal/binary"
|
||||
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -21,3 +21,524 @@ func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
||||
// Very simple for the attiny85, which only has a single port.
|
||||
return avr.PORTB, 1 << uint8(p)
|
||||
}
|
||||
|
||||
// PWM is one PWM peripheral, which consists of a counter and two output
|
||||
// channels (that can be connected to two fixed pins). You can set the frequency
|
||||
// using SetPeriod, but only for all the channels in this PWM peripheral at
|
||||
// once.
|
||||
type PWM struct {
|
||||
num uint8
|
||||
}
|
||||
|
||||
var (
|
||||
Timer0 = PWM{0} // 8 bit timer for PB0 and PB1
|
||||
Timer1 = PWM{1} // 8 bit high-speed timer for PB1 and PB4
|
||||
)
|
||||
|
||||
// GTCCR bits for Timer1 that are not defined in the device file
|
||||
const (
|
||||
gtccrPWM1B = 0x40 // Pulse Width Modulator B Enable
|
||||
gtccrCOM1B0 = 0x10 // Comparator B Output Mode bit 0
|
||||
gtccrCOM1B1 = 0x20 // Comparator B Output Mode bit 1
|
||||
)
|
||||
|
||||
// Configure enables and configures this PWM.
|
||||
//
|
||||
// For Timer0, there is only a limited number of periods available, namely the
|
||||
// CPU frequency divided by 256 and again divided by 1, 8, 64, 256, or 1024.
|
||||
// For a MCU running at 8MHz, this would be a period of 32µs, 256µs, 2048µs,
|
||||
// 8192µs, or 32768µs.
|
||||
//
|
||||
// For Timer1, the period is more flexible as it uses OCR1C as the top value.
|
||||
// Timer1 also supports more prescaler values (1 to 16384).
|
||||
func (pwm PWM) Configure(config PWMConfig) error {
|
||||
switch pwm.num {
|
||||
case 0: // Timer/Counter 0 (8-bit)
|
||||
// Calculate the timer prescaler.
|
||||
var prescaler uint8
|
||||
switch config.Period {
|
||||
case 0, (uint64(1e9) * 256 * 1) / uint64(CPUFrequency()):
|
||||
prescaler = 1
|
||||
case (uint64(1e9) * 256 * 8) / uint64(CPUFrequency()):
|
||||
prescaler = 2
|
||||
case (uint64(1e9) * 256 * 64) / uint64(CPUFrequency()):
|
||||
prescaler = 3
|
||||
case (uint64(1e9) * 256 * 256) / uint64(CPUFrequency()):
|
||||
prescaler = 4
|
||||
case (uint64(1e9) * 256 * 1024) / uint64(CPUFrequency()):
|
||||
prescaler = 5
|
||||
default:
|
||||
return ErrPWMPeriodTooLong
|
||||
}
|
||||
|
||||
avr.TCCR0B.Set(prescaler)
|
||||
// Set the PWM mode to fast PWM (mode = 3).
|
||||
avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01)
|
||||
|
||||
case 1: // Timer/Counter 1 (8-bit high-speed)
|
||||
// Timer1 on ATtiny85 is different from ATmega328:
|
||||
// - It's 8-bit with configurable top (OCR1C)
|
||||
// - Has more prescaler options (1-16384)
|
||||
// - PWM mode is enabled per-channel via PWM1A/PWM1B bits
|
||||
var top uint64
|
||||
if config.Period == 0 {
|
||||
// Use a top appropriate for LEDs.
|
||||
top = 0xff
|
||||
} else {
|
||||
// Calculate top value: top = period * (CPUFrequency / 1e9)
|
||||
top = config.Period * (uint64(CPUFrequency()) / 1000000) / 1000
|
||||
}
|
||||
|
||||
// Timer1 prescaler values: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384
|
||||
const maxTop = 256
|
||||
var prescaler uint8
|
||||
switch {
|
||||
case top <= maxTop:
|
||||
prescaler = 1 // prescaler 1
|
||||
case top/2 <= maxTop:
|
||||
prescaler = 2 // prescaler 2
|
||||
top /= 2
|
||||
case top/4 <= maxTop:
|
||||
prescaler = 3 // prescaler 4
|
||||
top /= 4
|
||||
case top/8 <= maxTop:
|
||||
prescaler = 4 // prescaler 8
|
||||
top /= 8
|
||||
case top/16 <= maxTop:
|
||||
prescaler = 5 // prescaler 16
|
||||
top /= 16
|
||||
case top/32 <= maxTop:
|
||||
prescaler = 6 // prescaler 32
|
||||
top /= 32
|
||||
case top/64 <= maxTop:
|
||||
prescaler = 7 // prescaler 64
|
||||
top /= 64
|
||||
case top/128 <= maxTop:
|
||||
prescaler = 8 // prescaler 128
|
||||
top /= 128
|
||||
case top/256 <= maxTop:
|
||||
prescaler = 9 // prescaler 256
|
||||
top /= 256
|
||||
case top/512 <= maxTop:
|
||||
prescaler = 10 // prescaler 512
|
||||
top /= 512
|
||||
case top/1024 <= maxTop:
|
||||
prescaler = 11 // prescaler 1024
|
||||
top /= 1024
|
||||
case top/2048 <= maxTop:
|
||||
prescaler = 12 // prescaler 2048
|
||||
top /= 2048
|
||||
case top/4096 <= maxTop:
|
||||
prescaler = 13 // prescaler 4096
|
||||
top /= 4096
|
||||
case top/8192 <= maxTop:
|
||||
prescaler = 14 // prescaler 8192
|
||||
top /= 8192
|
||||
case top/16384 <= maxTop:
|
||||
prescaler = 15 // prescaler 16384
|
||||
top /= 16384
|
||||
default:
|
||||
return ErrPWMPeriodTooLong
|
||||
}
|
||||
|
||||
// Set prescaler (CS1[3:0] bits)
|
||||
avr.TCCR1.Set(prescaler)
|
||||
// Set top value
|
||||
avr.OCR1C.Set(uint8(top - 1))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetPeriod updates the period of this PWM peripheral.
|
||||
// To set a particular frequency, use the following formula:
|
||||
//
|
||||
// period = 1e9 / frequency
|
||||
//
|
||||
// If you use a period of 0, a period that works well for LEDs will be picked.
|
||||
//
|
||||
// SetPeriod will not change the prescaler, but also won't change the current
|
||||
// value in any of the channels. This means that you may need to update the
|
||||
// value for the particular channel.
|
||||
//
|
||||
// Note that you cannot pick any arbitrary period after the PWM peripheral has
|
||||
// been configured. If you want to switch between frequencies, pick the lowest
|
||||
// frequency (longest period) once when calling Configure and adjust the
|
||||
// frequency here as needed.
|
||||
func (pwm PWM) SetPeriod(period uint64) error {
|
||||
if pwm.num == 0 {
|
||||
return ErrPWMPeriodTooLong // Timer0 doesn't support dynamic period
|
||||
}
|
||||
|
||||
// Timer1 can adjust period via OCR1C
|
||||
var top uint64
|
||||
if period == 0 {
|
||||
top = 0xff
|
||||
} else {
|
||||
top = period * (uint64(CPUFrequency()) / 1000000) / 1000
|
||||
}
|
||||
|
||||
// Get current prescaler
|
||||
prescaler := avr.TCCR1.Get() & 0x0f
|
||||
// Timer1 prescaler values follow a power-of-2 pattern:
|
||||
// prescaler n maps to divisor 2^(n-1), so we can use a simple shift
|
||||
if prescaler > 0 && prescaler <= 15 {
|
||||
top >>= (prescaler - 1)
|
||||
}
|
||||
|
||||
if top > 256 {
|
||||
return ErrPWMPeriodTooLong
|
||||
}
|
||||
|
||||
avr.OCR1C.Set(uint8(top - 1))
|
||||
avr.TCNT1.Set(0)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Top returns the current counter top, for use in duty cycle calculation. It
|
||||
// will only change with a call to Configure or SetPeriod, otherwise it is
|
||||
// constant.
|
||||
//
|
||||
// The value returned here is hardware dependent. In general, it's best to treat
|
||||
// it as an opaque value that can be divided by some number and passed to Set
|
||||
// (see Set documentation for more information).
|
||||
func (pwm PWM) Top() uint32 {
|
||||
if pwm.num == 1 {
|
||||
// Timer1 has configurable top via OCR1C
|
||||
return uint32(avr.OCR1C.Get()) + 1
|
||||
}
|
||||
// Timer0 goes from 0 to 0xff (256 in total)
|
||||
return 256
|
||||
}
|
||||
|
||||
// Counter returns the current counter value of the timer in this PWM
|
||||
// peripheral. It may be useful for debugging.
|
||||
func (pwm PWM) Counter() uint32 {
|
||||
switch pwm.num {
|
||||
case 0:
|
||||
return uint32(avr.TCNT0.Get())
|
||||
case 1:
|
||||
return uint32(avr.TCNT1.Get())
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Prescaler lookup tables using uint16 (more efficient than uint64 on AVR)
|
||||
// Timer0 prescaler lookup table (index 0-7 maps to prescaler bits)
|
||||
var timer0Prescalers = [8]uint16{0, 1, 8, 64, 256, 1024, 0, 0}
|
||||
|
||||
// Timer1 prescaler lookup table (index 0-15 maps to prescaler bits)
|
||||
var timer1Prescalers = [16]uint16{0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384}
|
||||
|
||||
// Period returns the used PWM period in nanoseconds. It might deviate slightly
|
||||
// from the configured period due to rounding.
|
||||
func (pwm PWM) Period() uint64 {
|
||||
var prescaler uint64
|
||||
switch pwm.num {
|
||||
case 0:
|
||||
prescalerBits := avr.TCCR0B.Get() & 0x7
|
||||
prescaler = uint64(timer0Prescalers[prescalerBits])
|
||||
if prescaler == 0 {
|
||||
return 0
|
||||
}
|
||||
case 1:
|
||||
prescalerBits := avr.TCCR1.Get() & 0x0f
|
||||
prescaler = uint64(timer1Prescalers[prescalerBits])
|
||||
if prescaler == 0 {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
top := uint64(pwm.Top())
|
||||
return prescaler * top * 1000 / uint64(CPUFrequency()/1e6)
|
||||
}
|
||||
|
||||
// Channel returns a PWM channel for the given pin.
|
||||
func (pwm PWM) Channel(pin Pin) (uint8, error) {
|
||||
pin.Configure(PinConfig{Mode: PinOutput})
|
||||
pin.Low()
|
||||
switch pwm.num {
|
||||
case 0:
|
||||
switch pin {
|
||||
case PB0: // OC0A
|
||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1)
|
||||
return 0, nil
|
||||
case PB1: // OC0B
|
||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
|
||||
return 1, nil
|
||||
}
|
||||
case 1:
|
||||
switch pin {
|
||||
case PB1: // OC1A
|
||||
// Enable PWM on channel A
|
||||
avr.TCCR1.SetBits(avr.TCCR1_PWM1A | avr.TCCR1_COM1A1)
|
||||
return 0, nil
|
||||
case PB4: // OC1B
|
||||
// Enable PWM on channel B (controlled via GTCCR)
|
||||
avr.GTCCR.SetBits(gtccrPWM1B | gtccrCOM1B1)
|
||||
return 1, nil
|
||||
}
|
||||
}
|
||||
return 0, ErrInvalidOutputPin
|
||||
}
|
||||
|
||||
// SetInverting sets whether to invert the output of this channel.
|
||||
// Without inverting, a 25% duty cycle would mean the output is high for 25% of
|
||||
// the time and low for the rest. Inverting flips the output as if a NOT gate
|
||||
// was placed at the output, meaning that the output would be 25% low and 75%
|
||||
// high with a duty cycle of 25%.
|
||||
func (pwm PWM) SetInverting(channel uint8, inverting bool) {
|
||||
switch pwm.num {
|
||||
case 0:
|
||||
switch channel {
|
||||
case 0: // channel A, PB0
|
||||
if inverting {
|
||||
avr.PORTB.SetBits(1 << 0)
|
||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A0)
|
||||
} else {
|
||||
avr.PORTB.ClearBits(1 << 0)
|
||||
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A0)
|
||||
}
|
||||
case 1: // channel B, PB1
|
||||
if inverting {
|
||||
avr.PORTB.SetBits(1 << 1)
|
||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B0)
|
||||
} else {
|
||||
avr.PORTB.ClearBits(1 << 1)
|
||||
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B0)
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
switch channel {
|
||||
case 0: // channel A, PB1
|
||||
if inverting {
|
||||
avr.PORTB.SetBits(1 << 1)
|
||||
avr.TCCR1.SetBits(avr.TCCR1_COM1A0)
|
||||
} else {
|
||||
avr.PORTB.ClearBits(1 << 1)
|
||||
avr.TCCR1.ClearBits(avr.TCCR1_COM1A0)
|
||||
}
|
||||
case 1: // channel B, PB4
|
||||
if inverting {
|
||||
avr.PORTB.SetBits(1 << 4)
|
||||
avr.GTCCR.SetBits(gtccrCOM1B0)
|
||||
} else {
|
||||
avr.PORTB.ClearBits(1 << 4)
|
||||
avr.GTCCR.ClearBits(gtccrCOM1B0)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set updates the channel value. This is used to control the channel duty
|
||||
// cycle, in other words the fraction of time the channel output is high (or low
|
||||
// when inverted). For example, to set it to a 25% duty cycle, use:
|
||||
//
|
||||
// pwm.Set(channel, pwm.Top() / 4)
|
||||
//
|
||||
// pwm.Set(channel, 0) will set the output to low and pwm.Set(channel,
|
||||
// pwm.Top()) will set the output to high, assuming the output isn't inverted.
|
||||
func (pwm PWM) Set(channel uint8, value uint32) {
|
||||
switch pwm.num {
|
||||
case 0:
|
||||
switch channel {
|
||||
case 0: // channel A, PB0
|
||||
if value == 0 {
|
||||
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A1)
|
||||
} else {
|
||||
avr.OCR0A.Set(uint8(value - 1))
|
||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1)
|
||||
}
|
||||
case 1: // channel B, PB1
|
||||
if value == 0 {
|
||||
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B1)
|
||||
} else {
|
||||
avr.OCR0B.Set(uint8(value - 1))
|
||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
switch channel {
|
||||
case 0: // channel A, PB1
|
||||
if value == 0 {
|
||||
avr.TCCR1.ClearBits(avr.TCCR1_COM1A1)
|
||||
} else {
|
||||
avr.OCR1A.Set(uint8(value - 1))
|
||||
avr.TCCR1.SetBits(avr.TCCR1_COM1A1)
|
||||
}
|
||||
case 1: // channel B, PB4
|
||||
if value == 0 {
|
||||
avr.GTCCR.ClearBits(gtccrCOM1B1)
|
||||
} else {
|
||||
avr.OCR1B.Set(uint8(value - 1))
|
||||
avr.GTCCR.SetBits(gtccrCOM1B1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SPIConfig is used to store config info for SPI.
|
||||
type SPIConfig struct {
|
||||
Frequency uint32
|
||||
LSBFirst bool
|
||||
Mode uint8
|
||||
}
|
||||
|
||||
// SPI is the USI-based SPI implementation for ATTiny85.
|
||||
// The ATTiny85 doesn't have dedicated SPI hardware, but uses the USI
|
||||
// (Universal Serial Interface) in three-wire mode.
|
||||
//
|
||||
// Fixed pin mapping (directly controlled by USI hardware):
|
||||
// - PB2: SCK (clock)
|
||||
// - PB1: DO/MOSI (data out)
|
||||
// - PB0: DI/MISO (data in)
|
||||
//
|
||||
// Note: CS pin must be managed by the user.
|
||||
type SPI struct {
|
||||
// Delay cycles for frequency control (0 = max speed)
|
||||
delayCycles uint16
|
||||
|
||||
// USICR value configured for the selected SPI mode
|
||||
usicrValue uint8
|
||||
|
||||
// LSB-first mode (requires software bit reversal)
|
||||
lsbFirst bool
|
||||
}
|
||||
|
||||
// SPI0 is the USI-based SPI interface on the ATTiny85
|
||||
var SPI0 = SPI{}
|
||||
|
||||
// Configure sets up the USI for SPI communication.
|
||||
// Note: The user must configure and control the CS pin separately.
|
||||
func (s *SPI) Configure(config SPIConfig) error {
|
||||
// Configure USI pins (fixed by hardware)
|
||||
// PB1 (DO/MOSI) -> OUTPUT
|
||||
// PB2 (USCK/SCK) -> OUTPUT
|
||||
// PB0 (DI/MISO) -> INPUT
|
||||
PB1.Configure(PinConfig{Mode: PinOutput})
|
||||
PB2.Configure(PinConfig{Mode: PinOutput})
|
||||
PB0.Configure(PinConfig{Mode: PinInput})
|
||||
|
||||
// Reset USI registers
|
||||
avr.USIDR.Set(0)
|
||||
avr.USISR.Set(0)
|
||||
|
||||
// Configure USI for SPI mode:
|
||||
// - USIWM0: Three-wire mode (SPI)
|
||||
// - USICS1: External clock source (software controlled via USITC)
|
||||
// - USICLK: Clock strobe - enables counter increment on USITC toggle
|
||||
// - USICS0: Controls clock phase (CPHA)
|
||||
//
|
||||
// SPI Modes:
|
||||
// Mode 0 (CPOL=0, CPHA=0): Clock idle low, sample on rising edge
|
||||
// Mode 1 (CPOL=0, CPHA=1): Clock idle low, sample on falling edge
|
||||
// Mode 2 (CPOL=1, CPHA=0): Clock idle high, sample on falling edge
|
||||
// Mode 3 (CPOL=1, CPHA=1): Clock idle high, sample on rising edge
|
||||
//
|
||||
// For USI, USICS0 controls the sampling edge when USICS1=1:
|
||||
// USICS0=0: Positive edge (rising)
|
||||
// USICS0=1: Negative edge (falling)
|
||||
switch config.Mode {
|
||||
case Mode0: // CPOL=0, CPHA=0: idle low, sample rising
|
||||
PB2.Low()
|
||||
s.usicrValue = avr.USICR_USIWM0 | avr.USICR_USICS1 | avr.USICR_USICLK
|
||||
case Mode1: // CPOL=0, CPHA=1: idle low, sample falling
|
||||
PB2.Low()
|
||||
s.usicrValue = avr.USICR_USIWM0 | avr.USICR_USICS1 | avr.USICR_USICS0 | avr.USICR_USICLK
|
||||
case Mode2: // CPOL=1, CPHA=0: idle high, sample falling
|
||||
PB2.High()
|
||||
s.usicrValue = avr.USICR_USIWM0 | avr.USICR_USICS1 | avr.USICR_USICS0 | avr.USICR_USICLK
|
||||
case Mode3: // CPOL=1, CPHA=1: idle high, sample rising
|
||||
PB2.High()
|
||||
s.usicrValue = avr.USICR_USIWM0 | avr.USICR_USICS1 | avr.USICR_USICLK
|
||||
default: // Default to Mode 0
|
||||
PB2.Low()
|
||||
s.usicrValue = avr.USICR_USIWM0 | avr.USICR_USICS1 | avr.USICR_USICLK
|
||||
}
|
||||
avr.USICR.Set(s.usicrValue)
|
||||
|
||||
// Calculate delay cycles for frequency control
|
||||
// Each bit transfer requires 2 clock toggles (rising + falling edge)
|
||||
// The loop overhead is approximately 10-15 cycles per toggle on AVR
|
||||
// We calculate additional delay cycles needed to achieve the target frequency
|
||||
if config.Frequency > 0 && config.Frequency < CPUFrequency()/2 {
|
||||
// Cycles per half-period = CPUFrequency / (2 * Frequency)
|
||||
// Subtract loop overhead (~15 cycles) to get delay cycles
|
||||
cyclesPerHalfPeriod := CPUFrequency() / (2 * config.Frequency)
|
||||
const loopOverhead = 15
|
||||
if cyclesPerHalfPeriod > loopOverhead {
|
||||
s.delayCycles = uint16(cyclesPerHalfPeriod - loopOverhead)
|
||||
} else {
|
||||
s.delayCycles = 0
|
||||
}
|
||||
} else {
|
||||
// Max speed - no delay
|
||||
s.delayCycles = 0
|
||||
}
|
||||
|
||||
// Store LSBFirst setting for use in Transfer
|
||||
s.lsbFirst = config.LSBFirst
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// reverseByte reverses the bit order of a byte (MSB <-> LSB)
|
||||
// Used for LSB-first SPI mode since USI hardware only supports MSB-first
|
||||
func reverseByte(b byte) byte {
|
||||
b = (b&0xF0)>>4 | (b&0x0F)<<4
|
||||
b = (b&0xCC)>>2 | (b&0x33)<<2
|
||||
b = (b&0xAA)>>1 | (b&0x55)<<1
|
||||
return b
|
||||
}
|
||||
|
||||
// Transfer performs a single byte SPI transfer (send and receive simultaneously)
|
||||
// This implements the USI-based SPI transfer using the "clock strobing" technique
|
||||
func (s *SPI) Transfer(b byte) (byte, error) {
|
||||
// For LSB-first mode, reverse the bits before sending
|
||||
// USI hardware only supports MSB-first, so we do it in software
|
||||
if s.lsbFirst {
|
||||
b = reverseByte(b)
|
||||
}
|
||||
|
||||
// Load the byte to transmit into the USI Data Register
|
||||
avr.USIDR.Set(b)
|
||||
|
||||
// Clear the counter overflow flag by writing 1 to it (AVR quirk)
|
||||
// This also resets the 4-bit counter to 0
|
||||
avr.USISR.Set(avr.USISR_USIOIF)
|
||||
|
||||
// Clock the data out/in
|
||||
// We need 16 clock toggles (8 bits × 2 edges per bit)
|
||||
// The USI counter counts each clock edge, so it overflows at 16
|
||||
// After 16 toggles, the clock returns to its idle state (set by CPOL in Configure)
|
||||
//
|
||||
// IMPORTANT: Only toggle USITC here!
|
||||
// - USITC toggles the clock pin
|
||||
// - The USICR mode bits (USIWM0, USICS1, USICS0, USICLK) were set in Configure()
|
||||
// - SetBits preserves those bits and only sets USITC
|
||||
if s.delayCycles == 0 {
|
||||
// Fast path: no delay, run at maximum speed
|
||||
for !avr.USISR.HasBits(avr.USISR_USIOIF) {
|
||||
avr.USICR.SetBits(avr.USICR_USITC)
|
||||
}
|
||||
} else {
|
||||
// Frequency-controlled path: add delay between clock toggles
|
||||
for !avr.USISR.HasBits(avr.USISR_USIOIF) {
|
||||
avr.USICR.SetBits(avr.USICR_USITC)
|
||||
// Delay loop for frequency control
|
||||
// Each iteration is approximately 3 cycles on AVR (dec, brne)
|
||||
for i := s.delayCycles; i > 0; i-- {
|
||||
avr.Asm("nop")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the received byte
|
||||
result := avr.USIDR.Get()
|
||||
|
||||
// For LSB-first mode, reverse the received bits
|
||||
if s.lsbFirst {
|
||||
result = reverseByte(result)
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
+43
-109
@@ -27,16 +27,29 @@ const (
|
||||
PinInput
|
||||
PinInputPullup
|
||||
PinInputPulldown
|
||||
PinAnalog
|
||||
)
|
||||
|
||||
const (
|
||||
GPIO0 Pin = 0
|
||||
GPIO1 Pin = 1
|
||||
GPIO2 Pin = 2
|
||||
GPIO3 Pin = 3
|
||||
GPIO4 Pin = 4
|
||||
GPIO5 Pin = 5
|
||||
GPIO6 Pin = 6
|
||||
)
|
||||
|
||||
const (
|
||||
ADC0 Pin = GPIO0
|
||||
ADC1 Pin = GPIO1
|
||||
ADC2 Pin = GPIO2
|
||||
ADC3 Pin = GPIO3
|
||||
ADC4 Pin = GPIO4
|
||||
ADC5 Pin = GPIO5 // avoid when WiFi is used.
|
||||
)
|
||||
|
||||
const (
|
||||
GPIO0 Pin = 0
|
||||
GPIO1 Pin = 1
|
||||
GPIO2 Pin = 2
|
||||
GPIO3 Pin = 3
|
||||
GPIO4 Pin = 4
|
||||
GPIO5 Pin = 5
|
||||
GPIO6 Pin = 6
|
||||
GPIO7 Pin = 7
|
||||
GPIO8 Pin = 8
|
||||
GPIO9 Pin = 9
|
||||
@@ -76,13 +89,15 @@ func (p Pin) Configure(config PinConfig) {
|
||||
const function = 1 // function 1 is GPIO for every pin
|
||||
muxConfig |= function << esp.IO_MUX_GPIO_MCU_SEL_Pos
|
||||
|
||||
// Make this pin an input pin (always).
|
||||
muxConfig |= esp.IO_MUX_GPIO_FUN_IE
|
||||
// FUN_IE: disable for PinAnalog (high-Z for ADC)
|
||||
if config.Mode != PinAnalog {
|
||||
muxConfig |= esp.IO_MUX_GPIO_FUN_IE
|
||||
}
|
||||
|
||||
// Set drive strength: 0 is lowest, 3 is highest.
|
||||
muxConfig |= 2 << esp.IO_MUX_GPIO_FUN_DRV_Pos
|
||||
|
||||
// Select pull mode.
|
||||
// Select pull mode (no pulls for PinAnalog).
|
||||
if config.Mode == PinInputPullup {
|
||||
muxConfig |= esp.IO_MUX_GPIO_FUN_WPU
|
||||
} else if config.Mode == PinInputPulldown {
|
||||
@@ -99,12 +114,27 @@ func (p Pin) Configure(config PinConfig) {
|
||||
case PinOutput:
|
||||
// Set the 'output enable' bit.
|
||||
esp.GPIO.ENABLE_W1TS.Set(1 << p)
|
||||
case PinInput, PinInputPullup, PinInputPulldown:
|
||||
case PinInput, PinInputPullup, PinInputPulldown, PinAnalog:
|
||||
// Clear the 'output enable' bit.
|
||||
esp.GPIO.ENABLE_W1TC.Set(1 << p)
|
||||
}
|
||||
}
|
||||
|
||||
// configure is the same as Configure, but allows setting a specific GPIO matrix signal.
|
||||
func (p Pin) configure(config PinConfig, signal uint32) {
|
||||
p.Configure(config)
|
||||
if signal == 256 {
|
||||
return
|
||||
}
|
||||
if config.Mode == PinOutput {
|
||||
p.outFunc().Set(signal)
|
||||
} else {
|
||||
inFunc(signal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(p))
|
||||
}
|
||||
}
|
||||
|
||||
func initI2CExt1Clock() {}
|
||||
|
||||
// outFunc returns the FUNCx_OUT_SEL_CFG register used for configuring the
|
||||
// output function selection.
|
||||
func (p Pin) outFunc() *volatile.Register32 {
|
||||
@@ -231,13 +261,13 @@ func setupPinInterrupt() error {
|
||||
esp.INTERRUPT_CORE0.GPIO_INTERRUPT_PRO_MAP.Set(cpuInterruptFromPin)
|
||||
return interrupt.New(cpuInterruptFromPin, func(interrupt.Interrupt) {
|
||||
status := esp.GPIO.STATUS.Get()
|
||||
// Clear before processing so new edges during callbacks are not lost.
|
||||
esp.GPIO.STATUS_W1TC.Set(status)
|
||||
for i, mask := 0, uint32(1); i < maxPin; i, mask = i+1, mask<<1 {
|
||||
if (status&mask) != 0 && pinCallbacks[i] != nil {
|
||||
pinCallbacks[i](Pin(i))
|
||||
}
|
||||
}
|
||||
// clear interrupt bit
|
||||
esp.GPIO.STATUS_W1TC.SetBits(status)
|
||||
}).Enable()
|
||||
}
|
||||
|
||||
@@ -509,102 +539,6 @@ func (uart *UART) writeByte(b byte) error {
|
||||
|
||||
func (uart *UART) flush() {}
|
||||
|
||||
type Serialer interface {
|
||||
WriteByte(c byte) error
|
||||
Write(data []byte) (n int, err error)
|
||||
Configure(config UARTConfig) error
|
||||
Buffered() int
|
||||
ReadByte() (byte, error)
|
||||
DTR() bool
|
||||
RTS() bool
|
||||
}
|
||||
|
||||
func initUSB() {
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
// USB Serial/JTAG Controller
|
||||
// See esp32-c3_technical_reference_manual_en.pdf
|
||||
// pg. 736
|
||||
type USB_DEVICE struct {
|
||||
Bus *esp.USB_DEVICE_Type
|
||||
}
|
||||
|
||||
var (
|
||||
_USBCDC = &USB_DEVICE{
|
||||
Bus: esp.USB_DEVICE,
|
||||
}
|
||||
|
||||
USBCDC Serialer = _USBCDC
|
||||
)
|
||||
|
||||
var (
|
||||
errUSBWrongSize = errors.New("USB: invalid write size")
|
||||
errUSBCouldNotWriteAllData = errors.New("USB: could not write all data")
|
||||
errUSBBufferEmpty = errors.New("USB: read buffer empty")
|
||||
)
|
||||
|
||||
func (usbdev *USB_DEVICE) Configure(config UARTConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (usbdev *USB_DEVICE) WriteByte(c byte) error {
|
||||
if usbdev.Bus.GetEP1_CONF_SERIAL_IN_EP_DATA_FREE() == 0 {
|
||||
return errUSBCouldNotWriteAllData
|
||||
}
|
||||
|
||||
usbdev.Bus.SetEP1_RDWR_BYTE(uint32(c))
|
||||
usbdev.flush()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (usbdev *USB_DEVICE) Write(data []byte) (n int, err error) {
|
||||
if len(data) == 0 || len(data) > 64 {
|
||||
return 0, errUSBWrongSize
|
||||
}
|
||||
|
||||
for i, c := range data {
|
||||
if usbdev.Bus.GetEP1_CONF_SERIAL_IN_EP_DATA_FREE() == 0 {
|
||||
if i > 0 {
|
||||
usbdev.flush()
|
||||
}
|
||||
|
||||
return i, errUSBCouldNotWriteAllData
|
||||
}
|
||||
usbdev.Bus.SetEP1_RDWR_BYTE(uint32(c))
|
||||
}
|
||||
|
||||
usbdev.flush()
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
func (usbdev *USB_DEVICE) Buffered() int {
|
||||
return int(usbdev.Bus.GetEP1_CONF_SERIAL_OUT_EP_DATA_AVAIL())
|
||||
}
|
||||
|
||||
func (usbdev *USB_DEVICE) ReadByte() (byte, error) {
|
||||
if usbdev.Bus.GetEP1_CONF_SERIAL_OUT_EP_DATA_AVAIL() != 0 {
|
||||
return byte(usbdev.Bus.GetEP1_RDWR_BYTE()), nil
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
func (usbdev *USB_DEVICE) DTR() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (usbdev *USB_DEVICE) RTS() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (usbdev *USB_DEVICE) flush() {
|
||||
usbdev.Bus.SetEP1_CONF_WR_DONE(1)
|
||||
for usbdev.Bus.GetEP1_CONF_SERIAL_IN_EP_DATA_FREE() == 0 {
|
||||
}
|
||||
}
|
||||
|
||||
// GetRNG returns 32-bit random numbers using the ESP32-C3 true random number generator,
|
||||
// Random numbers are generated based on the thermal noise in the system and the
|
||||
// asynchronous clock mismatch.
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
//go:build esp32c3 && !m5stamp_c3
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/esp"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// newRegI2C returns the regI2C configured for ESP32-C3: hostID=0, drefInit=1.
|
||||
func newRegI2C() regI2C { return regI2C{hostID: 0, drefInit: 1} }
|
||||
|
||||
const (
|
||||
// ADC attenuation values for ESP32-C3 APB_SARADC.
|
||||
// 0 dB : ~0 .. 1.1 V
|
||||
// 11 dB : ~0 .. 3.3 V (matches typical VDD)
|
||||
atten0dB = 0
|
||||
atten11dB = 3
|
||||
)
|
||||
|
||||
func InitADC() {
|
||||
esp.SYSTEM.SetPERIP_RST_EN0_APB_SARADC_RST(1)
|
||||
esp.SYSTEM.SetPERIP_CLK_EN0_APB_SARADC_CLK_EN(1)
|
||||
esp.SYSTEM.SetPERIP_RST_EN0_APB_SARADC_RST(0)
|
||||
|
||||
esp.RTC_CNTL.SetANA_CONF_SAR_I2C_PU(1)
|
||||
esp.RTC_CNTL.SetSENSOR_CTRL_FORCE_XPD_SAR(1)
|
||||
esp.APB_SARADC.SetCTRL_SARADC_XPD_SAR_FORCE(1)
|
||||
esp.APB_SARADC.SetFSM_WAIT_SARADC_XPD_WAIT(8)
|
||||
esp.APB_SARADC.SetFSM_WAIT_SARADC_RSTB_WAIT(8)
|
||||
esp.APB_SARADC.SetFSM_WAIT_SARADC_STANDBY_WAIT(100)
|
||||
esp.APB_SARADC.SetCLKM_CONF_CLK_SEL(2)
|
||||
esp.APB_SARADC.SetCLKM_CONF_CLKM_DIV_NUM(1)
|
||||
esp.APB_SARADC.SetCLKM_CONF_CLKM_DIV_B(0)
|
||||
esp.APB_SARADC.SetCLKM_CONF_CLKM_DIV_A(0)
|
||||
esp.APB_SARADC.SetCLKM_CONF_CLK_EN(1)
|
||||
|
||||
adcSelfCalibrate()
|
||||
}
|
||||
|
||||
// ESP32-C3: ADC1 = GPIO0–GPIO4 (ch 0–4), ADC2 = GPIO5 (ch 0). ADC2 shares with Wi‑Fi;
|
||||
// readings may be noisy when Wi‑Fi is active.
|
||||
func (a ADC) Configure(config ADCConfig) error {
|
||||
if a.Pin > 5 {
|
||||
return errors.New("invalid ADC pin for ESP32-C3")
|
||||
}
|
||||
a.Pin.Configure(PinConfig{Mode: PinAnalog})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a ADC) Get() uint16 {
|
||||
if a.Pin > 5 {
|
||||
return 0
|
||||
}
|
||||
adc1 := a.Pin <= 4
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_ATTEN(atten11dB)
|
||||
esp.APB_SARADC.SetINT_CLR_APB_SARADC1_DONE_INT_CLR(1)
|
||||
esp.APB_SARADC.SetINT_CLR_APB_SARADC2_DONE_INT_CLR(1)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_START(0)
|
||||
var raw uint32
|
||||
if adc1 {
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_CHANNEL(uint32(a.Pin))
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC1_ONETIME_SAMPLE(1)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_START(1)
|
||||
for esp.APB_SARADC.GetINT_RAW_APB_SARADC1_DONE_INT_RAW() == 0 {
|
||||
}
|
||||
raw = esp.APB_SARADC.GetSAR1DATA_STATUS_APB_SARADC1_DATA()
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_START(0)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC1_ONETIME_SAMPLE(0)
|
||||
} else {
|
||||
// ADC2: GPIO5 = channel 0. Grant arbiter to ADC2 first, then set channel and start.
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC1_ONETIME_SAMPLE(0)
|
||||
esp.APB_SARADC.SetARB_CTRL_ADC_ARB_APB_FORCE(1)
|
||||
esp.APB_SARADC.SetARB_CTRL_ADC_ARB_GRANT_FORCE(1)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_CHANNEL(8) // (1<<3)|0 for ADC2 channel 0
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC2_ONETIME_SAMPLE(1)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_START(1)
|
||||
for esp.APB_SARADC.GetINT_RAW_APB_SARADC2_DONE_INT_RAW() == 0 {
|
||||
}
|
||||
raw = esp.APB_SARADC.GetSAR2DATA_STATUS_APB_SARADC2_DATA()
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_START(0)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC2_ONETIME_SAMPLE(0)
|
||||
esp.APB_SARADC.SetARB_CTRL_ADC_ARB_APB_FORCE(0)
|
||||
esp.APB_SARADC.SetARB_CTRL_ADC_ARB_GRANT_FORCE(0)
|
||||
}
|
||||
return uint16(raw&0xfff) << 4
|
||||
}
|
||||
|
||||
// adcSelfCalibration
|
||||
const (
|
||||
adcCalTimesC3 = 15
|
||||
adcCalRtcMagicC3 = uint32(0xADC1C401)
|
||||
adcCalInitMinC3 = uint32(1000)
|
||||
adcCalInitMaxC3 = uint32(4096)
|
||||
)
|
||||
|
||||
// selfCalibrate sets ADC1/ADC2 init code from RTC or runs self-calibration (GND).
|
||||
// eFuse is not used: on ESP32-C3 the ADC calibration fields in BLK2 are often unprogrammed.
|
||||
func adcSelfCalibrate() {
|
||||
reg := newRegI2C()
|
||||
reg.sarEnable()
|
||||
|
||||
var adc1Code uint32
|
||||
if saved, ok := restoreFromRTC(); ok {
|
||||
adc1Code = saved
|
||||
} else {
|
||||
calSetupADC1()
|
||||
reg.calibrationInit(0)
|
||||
reg.calibrationPrepare(0)
|
||||
adc1Code = reg.calibrateBinarySearch(0, adcCalTimesC3, readADC1)
|
||||
if adc1Code < adcCalInitMinC3 {
|
||||
adc1Code = adcCalInitMinC3
|
||||
}
|
||||
if adc1Code > adcCalInitMaxC3 {
|
||||
adc1Code = adcCalInitMaxC3
|
||||
}
|
||||
saveToRTC(adc1Code)
|
||||
reg.calibrationFinish(0)
|
||||
}
|
||||
|
||||
applyADC1Code(reg, adc1Code)
|
||||
applyADC2Code(reg, adc1Code)
|
||||
}
|
||||
|
||||
// calSetupADC1 configures APB_SARADC for oneshot sampling on ADC1 channel 0
|
||||
// with fixed attenuation. This is used only during self‑calibration.
|
||||
func calSetupADC1() {
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_ATTEN(atten11dB)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_CHANNEL(0)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC1_ONETIME_SAMPLE(1)
|
||||
}
|
||||
|
||||
// calSetupADC2 configures APB_SARADC for oneshot sampling on ADC2 (GPIO5, ch 0).
|
||||
// On C3, onetime_channel = (unit<<3)|channel → ADC2 ch0 = 8.
|
||||
func calSetupADC2() {
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_ATTEN(atten11dB)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_CHANNEL(8) // (1<<3)|0 for ADC2
|
||||
esp.APB_SARADC.SetARB_CTRL_ADC_ARB_APB_FORCE(1)
|
||||
esp.APB_SARADC.SetARB_CTRL_ADC_ARB_GRANT_FORCE(1)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC2_ONETIME_SAMPLE(1)
|
||||
}
|
||||
|
||||
// readADC1 performs a single ADC1 conversion using the APB_SARADC
|
||||
// oneshot path and returns the raw 12‑bit result (0..4095).
|
||||
func readADC1() uint32 {
|
||||
esp.APB_SARADC.SetINT_CLR_APB_SARADC1_DONE_INT_CLR(1)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_START(0)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_START(1)
|
||||
for esp.APB_SARADC.GetINT_RAW_APB_SARADC1_DONE_INT_RAW() == 0 {
|
||||
}
|
||||
raw := esp.APB_SARADC.GetSAR1DATA_STATUS_APB_SARADC1_DATA() & 0xfff
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_START(0)
|
||||
return uint32(raw)
|
||||
}
|
||||
|
||||
// readADC2 performs a single ADC2 conversion and returns the raw 12‑bit result (0..4095).
|
||||
func readADC2() uint32 {
|
||||
esp.APB_SARADC.SetINT_CLR_APB_SARADC2_DONE_INT_CLR(1)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_START(0)
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_START(1)
|
||||
for esp.APB_SARADC.GetINT_RAW_APB_SARADC2_DONE_INT_RAW() == 0 {
|
||||
}
|
||||
raw := esp.APB_SARADC.GetSAR2DATA_STATUS_APB_SARADC2_DATA() & 0xfff
|
||||
esp.APB_SARADC.SetONETIME_SAMPLE_SARADC_ONETIME_START(0)
|
||||
esp.APB_SARADC.SetARB_CTRL_ADC_ARB_APB_FORCE(0)
|
||||
esp.APB_SARADC.SetARB_CTRL_ADC_ARB_GRANT_FORCE(0)
|
||||
return uint32(raw)
|
||||
}
|
||||
|
||||
func restoreFromRTC() (uint32, bool) {
|
||||
if esp.RTC_CNTL.GetSTORE0() != adcCalRtcMagicC3 {
|
||||
return 0, false
|
||||
}
|
||||
code := esp.RTC_CNTL.GetSTORE1()
|
||||
if code < adcCalInitMinC3 || code > adcCalInitMaxC3 {
|
||||
return 0, false
|
||||
}
|
||||
return code, true
|
||||
}
|
||||
|
||||
func saveToRTC(code uint32) {
|
||||
if code < adcCalInitMinC3 || code > adcCalInitMaxC3 {
|
||||
return
|
||||
}
|
||||
esp.RTC_CNTL.SetSTORE0(adcCalRtcMagicC3)
|
||||
esp.RTC_CNTL.SetSTORE1(code)
|
||||
}
|
||||
|
||||
// applyADC1Code sets ADC1 init code and finishes calibration.
|
||||
func applyADC1Code(reg regI2C, code uint32) {
|
||||
calSetupADC1()
|
||||
reg.calibrationInit(0)
|
||||
reg.calibrationPrepare(0)
|
||||
reg.setCalibrationParam(0, code)
|
||||
reg.calibrationFinish(0)
|
||||
}
|
||||
|
||||
// applyADC2Code sets ADC2 init code and finishes calibration. On C3 eFuse V1
|
||||
// there is no separate ADC2 calibration; IDF uses ADC1 init code for both units.
|
||||
func applyADC2Code(reg regI2C, code uint32) {
|
||||
reg.calibrationInit(1)
|
||||
reg.calibrationPrepare(1)
|
||||
reg.setCalibrationParam(1, code)
|
||||
reg.calibrationFinish(1)
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
//go:build esp32c3
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
/*
|
||||
#include <stdint.h>
|
||||
extern int esp_rom_spiflash_read(uint32_t src_addr, uint32_t *data, uint32_t len);
|
||||
extern int esp_rom_spiflash_write(uint32_t dest_addr, const uint32_t *data, uint32_t len);
|
||||
extern int esp_rom_spiflash_erase_sector(uint32_t sector_num);
|
||||
extern int esp_rom_spiflash_unlock(void);
|
||||
extern void Cache_Invalidate_Addr(uint32_t addr, uint32_t size);
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// 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)+uintptr(len(p)) > FlashDataEnd() {
|
||||
return 0, errFlashCannotReadPastEOF
|
||||
}
|
||||
|
||||
data := unsafe.Slice((*byte)(unsafe.Add(unsafe.Pointer(FlashDataStart()), 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 = 4
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
// return the correct address to be used for reads
|
||||
func readAddress(off int64) uintptr {
|
||||
return FlashDataStart() + uintptr(off)
|
||||
}
|
||||
|
||||
const flashDROMStart = 0x3C000000
|
||||
|
||||
// return the correct physical address to be used for write/erase
|
||||
func writeAddress(off int64) uint32 {
|
||||
// DROM maps 1:1 with flash physical offset, starting at 0x3C000000.
|
||||
return uint32(readAddress(off) - flashDROMStart)
|
||||
}
|
||||
|
||||
func (f flashBlockDevice) writeAt(p []byte, off int64) (n int, err error) {
|
||||
if readAddress(off)+uintptr(len(p)) > FlashDataEnd() {
|
||||
return 0, errFlashCannotWritePastEOF
|
||||
}
|
||||
|
||||
address := writeAddress(off)
|
||||
padded := flashPad(p, int(f.WriteBlockSize()))
|
||||
|
||||
state := interrupt.Disable()
|
||||
defer interrupt.Restore(state)
|
||||
|
||||
C.esp_rom_spiflash_unlock()
|
||||
res := C.esp_rom_spiflash_write(C.uint32_t(address), (*C.uint32_t)(unsafe.Pointer(&padded[0])), C.uint32_t(len(padded)))
|
||||
C.Cache_Invalidate_Addr(C.uint32_t(readAddress(off)), C.uint32_t(len(padded)))
|
||||
if res != 0 {
|
||||
return 0, errFlashCannotWriteData
|
||||
}
|
||||
|
||||
return len(padded), nil
|
||||
}
|
||||
|
||||
func (f flashBlockDevice) eraseBlocks(start, length int64) error {
|
||||
address := writeAddress(start * f.EraseBlockSize())
|
||||
if uintptr(unsafe.Add(unsafe.Pointer(uintptr(address)+flashDROMStart), length*f.EraseBlockSize())) > FlashDataEnd() {
|
||||
return errFlashCannotErasePastEOF
|
||||
}
|
||||
|
||||
state := interrupt.Disable()
|
||||
defer interrupt.Restore(state)
|
||||
|
||||
C.esp_rom_spiflash_unlock()
|
||||
sector := address / uint32(f.EraseBlockSize())
|
||||
|
||||
for i := int64(0); i < length; i++ {
|
||||
res := C.esp_rom_spiflash_erase_sector(C.uint32_t(sector + uint32(i)))
|
||||
C.Cache_Invalidate_Addr(C.uint32_t(readAddress((start+i)*f.EraseBlockSize())), C.uint32_t(f.EraseBlockSize()))
|
||||
if res != 0 {
|
||||
return errFlashCannotErasePage
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user