mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-07 04:23:41 +00:00
Compare commits
122 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6384ecace0 | |||
| 38881a2850 | |||
| 0f1cf14743 | |||
| 7c34f7704e | |||
| 377415a6c3 | |||
| 1e13c6d18f | |||
| 14121f4b0e | |||
| 7768195835 | |||
| c095b7e9c4 | |||
| 1f6d34d995 | |||
| 9951eb9990 | |||
| c8f77d26a8 | |||
| 8eaa9bd8d0 | |||
| 6061f3db92 | |||
| 410aa0e0d8 | |||
| c66836cf3a | |||
| ca9211b582 | |||
| cb7d470ba4 | |||
| 5baee9a8ee | |||
| c47f52b546 | |||
| a2588d8db3 | |||
| f529b6071d | |||
| 5557e97888 | |||
| d04b07fa8b | |||
| 7486277012 | |||
| 36d60b8349 | |||
| c55191283b | |||
| ad30085b93 | |||
| e9ca41735a | |||
| df1f83f4e1 | |||
| 5879d785a9 | |||
| 186018abeb | |||
| 828b9614c2 | |||
| f5e933cd4d | |||
| 0952b1b984 | |||
| ed55f56d85 | |||
| edb8766aab | |||
| 413bb55e2c | |||
| 0db1a4bec1 | |||
| 2867da164d | |||
| 7b8ae2d6b6 | |||
| 5b8127fd4e | |||
| cc3e785692 | |||
| 0ea5cfc8fe | |||
| 70f1a5429a | |||
| 2fb2113168 | |||
| cb39611389 | |||
| 45764325b4 | |||
| bb66232164 | |||
| 9679e7f1cc | |||
| 6cdfc298cf | |||
| 9a4bfd0e96 | |||
| ee3106be98 | |||
| 57f49af726 | |||
| 38a80b45d3 | |||
| e9003e2deb | |||
| 204659bdcd | |||
| 08ca1d13d0 | |||
| 53db436a7d | |||
| 0ad15551c8 | |||
| afd65e224a | |||
| 5f50c3b60b | |||
| 8858d49989 | |||
| cf39d8b2c8 | |||
| d92a31b440 | |||
| 9c77a38358 | |||
| d0445d6f83 | |||
| a40b11f535 | |||
| 8c90f4facf | |||
| c7c9a76af5 | |||
| 6984af43a0 | |||
| 81c56c3ab8 | |||
| 3d9a1ca22a | |||
| c2083014b3 | |||
| 603a81f194 | |||
| cfc32794a7 | |||
| 1d9c53d00e | |||
| 8d2a07b927 | |||
| ffe6dfd21b | |||
| cf21380264 | |||
| 534b3b0c0b | |||
| ceeb233ff6 | |||
| de3f0af829 | |||
| a511f18c64 | |||
| 731bd5cd1b | |||
| 4acf59546e | |||
| 2ee4d9aaa1 | |||
| b58b7c59ae | |||
| e14b6a7009 | |||
| a1a2d1ab81 | |||
| 07591178cd | |||
| 43bdc888dd | |||
| 4229e670ce | |||
| 76a7ad2a3e | |||
| e4f551ac7f | |||
| 338590cc75 | |||
| 22d70604d8 | |||
| c6add1e769 | |||
| c6609a02fa | |||
| a449c4813a | |||
| 19fb1bfafc | |||
| f91b6ad0df | |||
| 94459cefe5 | |||
| 803ba4f54d | |||
| 2919fa8b14 | |||
| 6420e90124 | |||
| 2d289addb7 | |||
| 4df145dcb4 | |||
| e065da20cb | |||
| d7c77b6761 | |||
| f51029484a | |||
| 03cfcbc17c | |||
| 649f49e000 | |||
| 3bcd4dc3e0 | |||
| 772c71ec27 | |||
| 9b896dc981 | |||
| d4189feca6 | |||
| 777048cfa9 | |||
| 2b215955ca | |||
| ce25f00769 | |||
| 1a59aecb63 | |||
| cca32e67a9 |
@@ -10,12 +10,12 @@ commands:
|
|||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- llvm-source-16-v3
|
- llvm-source-17-v1
|
||||||
- run:
|
- run:
|
||||||
name: "Fetch LLVM source"
|
name: "Fetch LLVM source"
|
||||||
command: make llvm-source
|
command: make llvm-source
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: llvm-source-16-v3
|
key: llvm-source-17-v1
|
||||||
paths:
|
paths:
|
||||||
- llvm-project/clang/lib/Headers
|
- llvm-project/clang/lib/Headers
|
||||||
- llvm-project/clang/include
|
- llvm-project/clang/include
|
||||||
@@ -75,10 +75,10 @@ commands:
|
|||||||
- run: go install -tags=llvm<<parameters.llvm>> .
|
- run: go install -tags=llvm<<parameters.llvm>> .
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- wasi-libc-sysroot-systemclang-v6
|
- wasi-libc-sysroot-systemclang-v7
|
||||||
- run: make wasi-libc
|
- run: make wasi-libc
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: wasi-libc-sysroot-systemclang-v6
|
key: wasi-libc-sysroot-systemclang-v7
|
||||||
paths:
|
paths:
|
||||||
- lib/wasi-libc/sysroot
|
- lib/wasi-libc/sysroot
|
||||||
- when:
|
- when:
|
||||||
@@ -105,9 +105,9 @@ jobs:
|
|||||||
- test-linux:
|
- test-linux:
|
||||||
llvm: "15"
|
llvm: "15"
|
||||||
resource_class: large
|
resource_class: large
|
||||||
test-llvm17-go121:
|
test-llvm17-go122:
|
||||||
docker:
|
docker:
|
||||||
- image: golang:1.21-bullseye
|
- image: golang:1.22-bullseye
|
||||||
steps:
|
steps:
|
||||||
- test-linux:
|
- test-linux:
|
||||||
llvm: "17"
|
llvm: "17"
|
||||||
@@ -119,5 +119,5 @@ workflows:
|
|||||||
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
# This tests our lowest supported versions of Go and LLVM, to make sure at
|
||||||
# least the smoke tests still pass.
|
# least the smoke tests still pass.
|
||||||
- test-llvm15-go118
|
- test-llvm15-go118
|
||||||
# This tests the upcoming LLVM 17 support.
|
# This tests LLVM 17 support when linking against system libraries.
|
||||||
- test-llvm17-go121
|
- test-llvm17-go122
|
||||||
|
|||||||
@@ -14,26 +14,36 @@ concurrency:
|
|||||||
jobs:
|
jobs:
|
||||||
build-macos:
|
build-macos:
|
||||||
name: build-macos
|
name: build-macos
|
||||||
runs-on: macos-11
|
strategy:
|
||||||
|
matrix:
|
||||||
|
# macos-12: amd64 (oldest supported version as of 05-02-2024)
|
||||||
|
# macos-14: arm64 (oldest arm64 version)
|
||||||
|
os: [macos-12, macos-14]
|
||||||
|
include:
|
||||||
|
- os: macos-12
|
||||||
|
goarch: amd64
|
||||||
|
- os: macos-14
|
||||||
|
goarch: arm64
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Install Dependencies
|
- name: Install Dependencies
|
||||||
shell: bash
|
shell: bash
|
||||||
run: |
|
run: |
|
||||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
|
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-macos-v1
|
key: llvm-source-17-${{ matrix.os }}-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -44,7 +54,7 @@ jobs:
|
|||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Save LLVM source cache
|
- name: Save LLVM source cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||||
@@ -55,10 +65,10 @@ jobs:
|
|||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- name: Restore LLVM build cache
|
- name: Restore LLVM build cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-16-macos-v1
|
key: llvm-build-17-${{ matrix.os }}-v1
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -73,16 +83,16 @@ jobs:
|
|||||||
make llvm-build
|
make llvm-build
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
- name: Save LLVM build cache
|
- name: Save LLVM build cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Cache wasi-libc sysroot
|
- name: Cache wasi-libc sysroot
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-v4
|
key: wasi-libc-sysroot-${{ matrix.os }}-v1
|
||||||
path: lib/wasi-libc/sysroot
|
path: lib/wasi-libc/sysroot
|
||||||
- name: Build wasi-libc
|
- name: Build wasi-libc
|
||||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||||
@@ -98,7 +108,7 @@ jobs:
|
|||||||
run: make tinygo-test
|
run: make tinygo-test
|
||||||
- name: Make release artifact
|
- name: Make release artifact
|
||||||
shell: bash
|
shell: bash
|
||||||
run: cp -p build/release.tar.gz build/tinygo.darwin-amd64.tar.gz
|
run: cp -p build/release.tar.gz build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
|
||||||
- name: Publish release artifact
|
- name: Publish release artifact
|
||||||
# Note: this release artifact is double-zipped, see:
|
# Note: this release artifact is double-zipped, see:
|
||||||
# https://github.com/actions/upload-artifact/issues/39
|
# https://github.com/actions/upload-artifact/issues/39
|
||||||
@@ -106,10 +116,10 @@ jobs:
|
|||||||
# - have a double-zipped artifact when downloaded from the UI
|
# - have a double-zipped artifact when downloaded from the UI
|
||||||
# - have a very slow artifact upload
|
# - have a very slow artifact upload
|
||||||
# We're doing the former here, to keep artifact uploads fast.
|
# We're doing the former here, to keep artifact uploads fast.
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: darwin-amd64-double-zipped
|
name: darwin-${{ matrix.goarch }}-double-zipped
|
||||||
path: build/tinygo.darwin-amd64.tar.gz
|
path: build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
|
||||||
- name: Smoke tests
|
- name: Smoke tests
|
||||||
shell: bash
|
shell: bash
|
||||||
run: make smoketest TINYGO=$(PWD)/build/tinygo
|
run: make smoketest TINYGO=$(PWD)/build/tinygo
|
||||||
@@ -120,31 +130,30 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
version: [16, 17]
|
version: [16, 17]
|
||||||
steps:
|
steps:
|
||||||
- name: Update Homebrew
|
- name: Set up Homebrew
|
||||||
run: brew update
|
uses: Homebrew/actions/setup-homebrew@master
|
||||||
- name: Fix Python symlinks
|
- name: Fix Python symlinks
|
||||||
run: |
|
run: |
|
||||||
# Github runners have broken symlinks, so relink
|
# Github runners have broken symlinks, so relink
|
||||||
# see: https://github.com/actions/setup-python/issues/577
|
# see: https://github.com/actions/setup-python/issues/577
|
||||||
brew unlink python
|
brew list -1 | grep python | while read formula; do brew unlink $formula; brew link --overwrite $formula; done
|
||||||
brew link --overwrite python
|
|
||||||
- name: Install LLVM
|
- name: Install LLVM
|
||||||
run: |
|
run: |
|
||||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.version }}
|
brew install llvm@${{ matrix.version }}
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Build TinyGo (LLVM ${{ matrix.version }})
|
- name: Build TinyGo (LLVM ${{ matrix.version }})
|
||||||
run: go install -tags=llvm${{ matrix.version }}
|
run: go install -tags=llvm${{ matrix.version }}
|
||||||
- name: Check binary
|
- name: Check binary
|
||||||
run: tinygo version
|
run: tinygo version
|
||||||
- name: Build TinyGo (default LLVM)
|
- name: Build TinyGo (default LLVM)
|
||||||
if: matrix.version == 16
|
if: matrix.version == 17
|
||||||
run: go install
|
run: go install
|
||||||
- name: Check binary
|
- name: Check binary
|
||||||
if: matrix.version == 16
|
if: matrix.version == 17
|
||||||
run: tinygo version
|
run: tinygo version
|
||||||
|
|||||||
@@ -19,15 +19,26 @@ jobs:
|
|||||||
packages: write
|
packages: write
|
||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
|
- name: Free Disk space
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
df -h
|
||||||
|
sudo rm -rf /opt/hostedtoolcache
|
||||||
|
sudo rm -rf /usr/local/lib/android
|
||||||
|
sudo rm -rf /usr/share/dotnet
|
||||||
|
sudo rm -rf /opt/ghc
|
||||||
|
sudo rm -rf /usr/local/graalvm
|
||||||
|
sudo rm -rf /usr/local/share/boost
|
||||||
|
df -h
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v4
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
tinygo/tinygo-dev
|
tinygo/tinygo-dev
|
||||||
@@ -36,24 +47,23 @@ jobs:
|
|||||||
type=sha,format=long
|
type=sha,format=long
|
||||||
type=raw,value=latest
|
type=raw,value=latest
|
||||||
- name: Log in to Docker Hub
|
- name: Log in to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||||
- name: Log in to Github Container Registry
|
- name: Log in to Github Container Registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v3
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
context: .
|
context: .
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
build-contexts: tinygo-llvm-build=docker-image://tinygo/llvm-16
|
|
||||||
cache-from: type=gha
|
cache-from: type=gha
|
||||||
cache-to: type=gha,mode=max
|
cache-to: type=gha,mode=max
|
||||||
- name: Trigger Drivers repo build on Github Actions
|
- name: Trigger Drivers repo build on Github Actions
|
||||||
|
|||||||
+44
-44
@@ -18,10 +18,10 @@ jobs:
|
|||||||
# statically linked binary.
|
# statically linked binary.
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container:
|
container:
|
||||||
image: golang:1.21-alpine
|
image: golang:1.22-alpine
|
||||||
steps:
|
steps:
|
||||||
- name: Install apk dependencies
|
- name: Install apk dependencies
|
||||||
# tar: needed for actions/cache@v3
|
# tar: needed for actions/cache@v4
|
||||||
# git+openssh: needed for checkout (I think?)
|
# git+openssh: needed for checkout (I think?)
|
||||||
# ruby: needed to install fpm
|
# ruby: needed to install fpm
|
||||||
run: apk add tar git openssh make g++ ruby
|
run: apk add tar git openssh make g++ ruby
|
||||||
@@ -29,21 +29,21 @@ jobs:
|
|||||||
# We're not on a multi-user machine, so this is safe.
|
# We're not on a multi-user machine, so this is safe.
|
||||||
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Cache Go
|
- name: Cache Go
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
|
key: go-cache-linux-alpine-v1-${{ hashFiles('go.mod') }}
|
||||||
path: |
|
path: |
|
||||||
~/.cache/go-build
|
~/.cache/go-build
|
||||||
~/go/pkg/mod
|
~/go/pkg/mod
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-linux-alpine-v1
|
key: llvm-source-17-linux-alpine-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Save LLVM source cache
|
- name: Save LLVM source cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||||
@@ -65,10 +65,10 @@ jobs:
|
|||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- name: Restore LLVM build cache
|
- name: Restore LLVM build cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-16-linux-alpine-v1
|
key: llvm-build-17-linux-alpine-v1
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -83,13 +83,13 @@ jobs:
|
|||||||
# Remove unnecessary object files (to reduce cache size).
|
# Remove unnecessary object files (to reduce cache size).
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
- name: Save LLVM build cache
|
- name: Save LLVM build cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Cache Binaryen
|
- name: Cache Binaryen
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-binaryen
|
id: cache-binaryen
|
||||||
with:
|
with:
|
||||||
key: binaryen-linux-alpine-v1
|
key: binaryen-linux-alpine-v1
|
||||||
@@ -100,10 +100,10 @@ jobs:
|
|||||||
apk add cmake samurai python3
|
apk add cmake samurai python3
|
||||||
make binaryen STATIC=1
|
make binaryen STATIC=1
|
||||||
- name: Cache wasi-libc
|
- name: Cache wasi-libc
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-linux-alpine-v1
|
key: wasi-libc-sysroot-linux-alpine-v2
|
||||||
path: lib/wasi-libc/sysroot
|
path: lib/wasi-libc/sysroot
|
||||||
- name: Build wasi-libc
|
- name: Build wasi-libc
|
||||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||||
@@ -119,7 +119,7 @@ jobs:
|
|||||||
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
|
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
|
||||||
cp -p build/release.deb /tmp/tinygo_amd64.deb
|
cp -p build/release.deb /tmp/tinygo_amd64.deb
|
||||||
- name: Publish release artifact
|
- name: Publish release artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: linux-amd64-double-zipped
|
name: linux-amd64-double-zipped
|
||||||
path: |
|
path: |
|
||||||
@@ -131,11 +131,11 @@ jobs:
|
|||||||
needs: build-linux
|
needs: build-linux
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Install wasmtime
|
- name: Install wasmtime
|
||||||
run: |
|
run: |
|
||||||
@@ -144,7 +144,7 @@ jobs:
|
|||||||
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
|
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
|
||||||
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
||||||
- name: Download release artifact
|
- name: Download release artifact
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: linux-amd64-double-zipped
|
name: linux-amd64-double-zipped
|
||||||
- name: Extract release tarball
|
- name: Extract release tarball
|
||||||
@@ -161,7 +161,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install apt dependencies
|
- name: Install apt dependencies
|
||||||
@@ -176,14 +176,14 @@ jobs:
|
|||||||
simavr \
|
simavr \
|
||||||
ninja-build
|
ninja-build
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v3
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: '16'
|
node-version: '18'
|
||||||
- name: Install wasmtime
|
- name: Install wasmtime
|
||||||
run: |
|
run: |
|
||||||
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
|
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
|
||||||
@@ -191,10 +191,10 @@ jobs:
|
|||||||
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
|
tar -C $HOME/.wasmtime/bin --wildcards -xf wasmtime-v14.0.4-x86_64-linux.tar.xz --strip-components=1 wasmtime-v14.0.4-x86_64-linux/*
|
||||||
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-linux-asserts-v1
|
key: llvm-source-17-linux-asserts-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -205,7 +205,7 @@ jobs:
|
|||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Save LLVM source cache
|
- name: Save LLVM source cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||||
@@ -216,10 +216,10 @@ jobs:
|
|||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- name: Restore LLVM build cache
|
- name: Restore LLVM build cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-16-linux-asserts-v1
|
key: llvm-build-17-linux-asserts-v1
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -232,13 +232,13 @@ jobs:
|
|||||||
# Remove unnecessary object files (to reduce cache size).
|
# Remove unnecessary object files (to reduce cache size).
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
- name: Save LLVM build cache
|
- name: Save LLVM build cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Cache Binaryen
|
- name: Cache Binaryen
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-binaryen
|
id: cache-binaryen
|
||||||
with:
|
with:
|
||||||
key: binaryen-linux-asserts-v1
|
key: binaryen-linux-asserts-v1
|
||||||
@@ -247,10 +247,10 @@ jobs:
|
|||||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
||||||
run: make binaryen
|
run: make binaryen
|
||||||
- name: Cache wasi-libc
|
- name: Cache wasi-libc
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-linux-asserts-v5
|
key: wasi-libc-sysroot-linux-asserts-v6
|
||||||
path: lib/wasi-libc/sysroot
|
path: lib/wasi-libc/sysroot
|
||||||
- name: Build wasi-libc
|
- name: Build wasi-libc
|
||||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||||
@@ -290,7 +290,7 @@ jobs:
|
|||||||
needs: build-linux
|
needs: build-linux
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install apt dependencies
|
- name: Install apt dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
@@ -299,15 +299,15 @@ jobs:
|
|||||||
g++-${{ matrix.toolchain }} \
|
g++-${{ matrix.toolchain }} \
|
||||||
libc6-dev-${{ matrix.libc }}-cross
|
libc6-dev-${{ matrix.libc }}-cross
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-linux-v1
|
key: llvm-source-17-linux-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -318,7 +318,7 @@ jobs:
|
|||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Save LLVM source cache
|
- name: Save LLVM source cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||||
@@ -329,10 +329,10 @@ jobs:
|
|||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- name: Restore LLVM build cache
|
- name: Restore LLVM build cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-16-linux-${{ matrix.goarch }}-v1
|
key: llvm-build-17-linux-${{ matrix.goarch }}-v1
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -347,13 +347,13 @@ jobs:
|
|||||||
# Remove unnecessary object files (to reduce cache size).
|
# Remove unnecessary object files (to reduce cache size).
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
- name: Save LLVM build cache
|
- name: Save LLVM build cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Cache Binaryen
|
- name: Cache Binaryen
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-binaryen
|
id: cache-binaryen
|
||||||
with:
|
with:
|
||||||
key: binaryen-linux-${{ matrix.goarch }}-v3
|
key: binaryen-linux-${{ matrix.goarch }}-v3
|
||||||
@@ -373,7 +373,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
make CROSS=${{ matrix.toolchain }}
|
make CROSS=${{ matrix.toolchain }}
|
||||||
- name: Download amd64 release
|
- name: Download amd64 release
|
||||||
uses: actions/download-artifact@v3
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: linux-amd64-double-zipped
|
name: linux-amd64-double-zipped
|
||||||
- name: Extract amd64 release
|
- name: Extract amd64 release
|
||||||
@@ -390,7 +390,7 @@ jobs:
|
|||||||
cp -p build/release.tar.gz /tmp/tinygo.linux-${{ matrix.goarch }}.tar.gz
|
cp -p build/release.tar.gz /tmp/tinygo.linux-${{ matrix.goarch }}.tar.gz
|
||||||
cp -p build/release.deb /tmp/tinygo_${{ matrix.libc }}.deb
|
cp -p build/release.deb /tmp/tinygo_${{ matrix.libc }}.deb
|
||||||
- name: Publish release artifact
|
- name: Publish release artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: linux-${{ matrix.goarch }}-double-zipped
|
name: linux-${{ matrix.goarch }}-double-zipped
|
||||||
path: |
|
path: |
|
||||||
|
|||||||
@@ -25,18 +25,18 @@ jobs:
|
|||||||
contents: read
|
contents: read
|
||||||
steps:
|
steps:
|
||||||
- name: Check out the repo
|
- name: Check out the repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v4
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
tinygo/llvm-16
|
tinygo/llvm-17
|
||||||
ghcr.io/${{ github.repository_owner }}/llvm-16
|
ghcr.io/${{ github.repository_owner }}/llvm-17
|
||||||
tags: |
|
tags: |
|
||||||
type=sha,format=long
|
type=sha,format=long
|
||||||
type=raw,value=latest
|
type=raw,value=latest
|
||||||
@@ -46,13 +46,13 @@ jobs:
|
|||||||
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||||
- name: Log in to Github Container Registry
|
- name: Log in to Github Container Registry
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
registry: ghcr.io
|
registry: ghcr.io
|
||||||
username: ${{ github.actor }}
|
username: ${{ github.actor }}
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v5
|
||||||
with:
|
with:
|
||||||
target: tinygo-llvm-build
|
target: tinygo-llvm-build
|
||||||
context: .
|
context: .
|
||||||
|
|||||||
@@ -16,22 +16,22 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Pull musl
|
- name: Pull musl
|
||||||
run: |
|
run: |
|
||||||
git submodule update --init lib/musl
|
git submodule update --init lib/musl
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-linux-nix-v1
|
key: llvm-source-17-linux-nix-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/compiler-rt
|
llvm-project/compiler-rt
|
||||||
- name: Download LLVM source
|
- name: Download LLVM source
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Save LLVM source cache
|
- name: Save LLVM source cache
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||||
|
|||||||
Executable
+12
@@ -0,0 +1,12 @@
|
|||||||
|
# Command that's part of sizediff.yml. This is put in a separate file so that it
|
||||||
|
# still works after checking out the dev branch (that is, when going from LLVM
|
||||||
|
# 16 to LLVM 17 for example, both Clang 16 and Clang 17 are installed).
|
||||||
|
|
||||||
|
echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main' | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||||
|
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install --no-install-recommends -y \
|
||||||
|
llvm-17-dev \
|
||||||
|
clang-17 \
|
||||||
|
libclang-17-dev \
|
||||||
|
lld-17
|
||||||
@@ -18,32 +18,24 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
echo "$HOME/go/bin" >> $GITHUB_PATH
|
echo "$HOME/go/bin" >> $GITHUB_PATH
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0 # fetch all history (no sparse checkout)
|
fetch-depth: 0 # fetch all history (no sparse checkout)
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install apt dependencies
|
- name: Install apt dependencies
|
||||||
run: |
|
run: ./.github/workflows/sizediff-install-pkgs.sh
|
||||||
echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main' | sudo tee /etc/apt/sources.list.d/llvm.list
|
|
||||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install --no-install-recommends -y \
|
|
||||||
llvm-16-dev \
|
|
||||||
clang-16 \
|
|
||||||
libclang-16-dev \
|
|
||||||
lld-16
|
|
||||||
- name: Restore LLVM source cache
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-sizediff-v1
|
key: llvm-source-17-sizediff-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/compiler-rt
|
llvm-project/compiler-rt
|
||||||
- name: Download LLVM source
|
- name: Download LLVM source
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Cache Go
|
- name: Cache Go
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
key: go-cache-linux-sizediff-v1-${{ hashFiles('go.mod') }}
|
key: go-cache-linux-sizediff-v1-${{ hashFiles('go.mod') }}
|
||||||
path: |
|
path: |
|
||||||
@@ -55,22 +47,25 @@ jobs:
|
|||||||
- name: Save HEAD
|
- name: Save HEAD
|
||||||
run: git branch github-actions-saved-HEAD HEAD
|
run: git branch github-actions-saved-HEAD HEAD
|
||||||
|
|
||||||
# Compute sizes for the dev branch
|
|
||||||
- name: Checkout dev branch
|
|
||||||
run: git checkout --no-recurse-submodules `git merge-base HEAD origin/dev`
|
|
||||||
- name: Build tinygo binary for the dev branch
|
|
||||||
run: go install
|
|
||||||
- name: Determine binary sizes on the dev branch
|
|
||||||
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-dev.txt)
|
|
||||||
|
|
||||||
# Compute sizes for the PR branch
|
# Compute sizes for the PR branch
|
||||||
- name: Checkout PR branch
|
|
||||||
run: git checkout --no-recurse-submodules github-actions-saved-HEAD
|
|
||||||
- name: Build tinygo binary for the PR branch
|
- name: Build tinygo binary for the PR branch
|
||||||
run: go install
|
run: go install
|
||||||
- name: Determine binary sizes on the PR branch
|
- name: Determine binary sizes on the PR branch
|
||||||
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-pr.txt)
|
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-pr.txt)
|
||||||
|
|
||||||
|
# Compute sizes for the dev branch
|
||||||
|
- name: Checkout dev branch
|
||||||
|
run: |
|
||||||
|
git reset --hard origin/dev
|
||||||
|
git checkout --no-recurse-submodules `git merge-base HEAD origin/dev`
|
||||||
|
- name: Install apt dependencies on the dev branch
|
||||||
|
# this is only needed on a PR that changes the LLVM version
|
||||||
|
run: ./.github/workflows/sizediff-install-pkgs.sh
|
||||||
|
- name: Build tinygo binary for the dev branch
|
||||||
|
run: go install
|
||||||
|
- name: Determine binary sizes on the dev branch
|
||||||
|
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-dev.txt)
|
||||||
|
|
||||||
# Create comment
|
# Create comment
|
||||||
# TODO: add a summary, something like:
|
# TODO: add a summary, something like:
|
||||||
# - overall size difference (percent)
|
# - overall size difference (percent)
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ jobs:
|
|||||||
runs-on: windows-2022
|
runs-on: windows-2022
|
||||||
steps:
|
steps:
|
||||||
- name: Configure pagefile
|
- name: Configure pagefile
|
||||||
uses: al-cheb/configure-pagefile-action@v1.3
|
uses: al-cheb/configure-pagefile-action@v1.4
|
||||||
with:
|
with:
|
||||||
minimum-size: 8GB
|
minimum-size: 8GB
|
||||||
maximum-size: 24GB
|
maximum-size: 24GB
|
||||||
@@ -29,19 +29,19 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
scoop install ninja binaryen
|
scoop install ninja binaryen
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
submodules: true
|
submodules: true
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Restore cached LLVM source
|
- name: Restore cached LLVM source
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
with:
|
with:
|
||||||
key: llvm-source-16-windows-v1
|
key: llvm-source-17-windows-v1
|
||||||
path: |
|
path: |
|
||||||
llvm-project/clang/lib/Headers
|
llvm-project/clang/lib/Headers
|
||||||
llvm-project/clang/include
|
llvm-project/clang/include
|
||||||
@@ -52,7 +52,7 @@ jobs:
|
|||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
run: make llvm-source
|
run: make llvm-source
|
||||||
- name: Save cached LLVM source
|
- name: Save cached LLVM source
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
|
||||||
@@ -63,10 +63,10 @@ jobs:
|
|||||||
llvm-project/lld/include
|
llvm-project/lld/include
|
||||||
llvm-project/llvm/include
|
llvm-project/llvm/include
|
||||||
- name: Restore cached LLVM build
|
- name: Restore cached LLVM build
|
||||||
uses: actions/cache/restore@v3
|
uses: actions/cache/restore@v4
|
||||||
id: cache-llvm-build
|
id: cache-llvm-build
|
||||||
with:
|
with:
|
||||||
key: llvm-build-16-windows-v2
|
key: llvm-build-17-windows-v1
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Build LLVM
|
- name: Build LLVM
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
@@ -80,16 +80,16 @@ jobs:
|
|||||||
# Remove unnecessary object files (to reduce cache size).
|
# Remove unnecessary object files (to reduce cache size).
|
||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
- name: Save cached LLVM build
|
- name: Save cached LLVM build
|
||||||
uses: actions/cache/save@v3
|
uses: actions/cache/save@v4
|
||||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||||
with:
|
with:
|
||||||
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
key: ${{ steps.cache-llvm-build.outputs.cache-primary-key }}
|
||||||
path: llvm-build
|
path: llvm-build
|
||||||
- name: Cache wasi-libc sysroot
|
- name: Cache wasi-libc sysroot
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
id: cache-wasi-libc
|
id: cache-wasi-libc
|
||||||
with:
|
with:
|
||||||
key: wasi-libc-sysroot-v4
|
key: wasi-libc-sysroot-v5
|
||||||
path: lib/wasi-libc/sysroot
|
path: lib/wasi-libc/sysroot
|
||||||
- name: Build wasi-libc
|
- name: Build wasi-libc
|
||||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||||
@@ -116,7 +116,7 @@ jobs:
|
|||||||
# - have a dobule-zipped artifact when downloaded from the UI
|
# - have a dobule-zipped artifact when downloaded from the UI
|
||||||
# - have a very slow artifact upload
|
# - have a very slow artifact upload
|
||||||
# We're doing the former here, to keep artifact uploads fast.
|
# We're doing the former here, to keep artifact uploads fast.
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: windows-amd64-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/release/release.zip
|
path: build/release/release.zip
|
||||||
@@ -126,7 +126,7 @@ jobs:
|
|||||||
needs: build-windows
|
needs: build-windows
|
||||||
steps:
|
steps:
|
||||||
- name: Configure pagefile
|
- name: Configure pagefile
|
||||||
uses: al-cheb/configure-pagefile-action@v1.3
|
uses: al-cheb/configure-pagefile-action@v1.4
|
||||||
with:
|
with:
|
||||||
minimum-size: 8GB
|
minimum-size: 8GB
|
||||||
maximum-size: 24GB
|
maximum-size: 24GB
|
||||||
@@ -139,14 +139,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
scoop install binaryen
|
scoop install binaryen
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: windows-amd64-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/
|
path: build/
|
||||||
@@ -163,20 +163,20 @@ jobs:
|
|||||||
needs: build-windows
|
needs: build-windows
|
||||||
steps:
|
steps:
|
||||||
- name: Configure pagefile
|
- name: Configure pagefile
|
||||||
uses: al-cheb/configure-pagefile-action@v1.3
|
uses: al-cheb/configure-pagefile-action@v1.4
|
||||||
with:
|
with:
|
||||||
minimum-size: 8GB
|
minimum-size: 8GB
|
||||||
maximum-size: 24GB
|
maximum-size: 24GB
|
||||||
disk-root: "C:"
|
disk-root: "C:"
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: windows-amd64-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/
|
path: build/
|
||||||
@@ -192,7 +192,7 @@ jobs:
|
|||||||
needs: build-windows
|
needs: build-windows
|
||||||
steps:
|
steps:
|
||||||
- name: Configure pagefile
|
- name: Configure pagefile
|
||||||
uses: al-cheb/configure-pagefile-action@v1.3
|
uses: al-cheb/configure-pagefile-action@v1.4
|
||||||
with:
|
with:
|
||||||
minimum-size: 8GB
|
minimum-size: 8GB
|
||||||
maximum-size: 24GB
|
maximum-size: 24GB
|
||||||
@@ -205,14 +205,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
scoop install binaryen && scoop install wasmtime@14.0.4
|
scoop install binaryen && scoop install wasmtime@14.0.4
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
- name: Install Go
|
- name: Install Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v5
|
||||||
with:
|
with:
|
||||||
go-version: '1.21'
|
go-version: '1.22'
|
||||||
cache: true
|
cache: true
|
||||||
- name: Download TinyGo build
|
- name: Download TinyGo build
|
||||||
uses: actions/download-artifact@v2
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: windows-amd64-double-zipped
|
name: windows-amd64-double-zipped
|
||||||
path: build/
|
path: build/
|
||||||
|
|||||||
+7
-2
@@ -9,10 +9,11 @@
|
|||||||
url = https://github.com/avr-rust/avr-mcu.git
|
url = https://github.com/avr-rust/avr-mcu.git
|
||||||
[submodule "lib/cmsis-svd"]
|
[submodule "lib/cmsis-svd"]
|
||||||
path = lib/cmsis-svd
|
path = lib/cmsis-svd
|
||||||
url = https://github.com/tinygo-org/cmsis-svd
|
url = https://github.com/cmsis-svd/cmsis-svd-data.git
|
||||||
|
branch = main
|
||||||
[submodule "lib/wasi-libc"]
|
[submodule "lib/wasi-libc"]
|
||||||
path = lib/wasi-libc
|
path = lib/wasi-libc
|
||||||
url = https://github.com/CraneStation/wasi-libc
|
url = https://github.com/WebAssembly/wasi-libc
|
||||||
[submodule "lib/picolibc"]
|
[submodule "lib/picolibc"]
|
||||||
path = lib/picolibc
|
path = lib/picolibc
|
||||||
url = https://github.com/keith-packard/picolibc.git
|
url = https://github.com/keith-packard/picolibc.git
|
||||||
@@ -34,3 +35,7 @@
|
|||||||
[submodule "lib/renesas-svd"]
|
[submodule "lib/renesas-svd"]
|
||||||
path = lib/renesas-svd
|
path = lib/renesas-svd
|
||||||
url = https://github.com/tinygo-org/renesas-svd.git
|
url = https://github.com/tinygo-org/renesas-svd.git
|
||||||
|
[submodule "src/net"]
|
||||||
|
path = src/net
|
||||||
|
url = https://github.com/tinygo-org/net.git
|
||||||
|
branch = dev
|
||||||
|
|||||||
+102
@@ -1,3 +1,105 @@
|
|||||||
|
0.31.2
|
||||||
|
---
|
||||||
|
|
||||||
|
* **general**
|
||||||
|
* update the `net` submodule to updated version with `Buffers` implementation
|
||||||
|
|
||||||
|
* **compiler**
|
||||||
|
* `syscall`: add wasm_unknown tag to some additional files so it can compile more code
|
||||||
|
|
||||||
|
* **standard library**
|
||||||
|
* `runtime`: add Frame.Entry field
|
||||||
|
|
||||||
|
|
||||||
|
0.31.1
|
||||||
|
---
|
||||||
|
|
||||||
|
* **general**
|
||||||
|
* fix Binaryen build in make task
|
||||||
|
* update final build stage of Docker `dev` image to go1.22
|
||||||
|
* only use GHA cache for building Docker `dev` image
|
||||||
|
* update the `net` submodule to latest version
|
||||||
|
|
||||||
|
* **compiler**
|
||||||
|
* `interp`: make getelementptr offsets signed
|
||||||
|
* `interp`: return a proper error message when indexing out of range
|
||||||
|
|
||||||
|
|
||||||
|
0.31.0
|
||||||
|
---
|
||||||
|
|
||||||
|
* **general**
|
||||||
|
* remove LLVM 14 support
|
||||||
|
* add LLVM 17 support, and use it by default
|
||||||
|
* add Nix flake support
|
||||||
|
* update bundled Binaryen to version 116
|
||||||
|
* add `ports` subcommand that lists available serial ports for `-port` and `-monitor`
|
||||||
|
* support wasmtime version 14
|
||||||
|
* add `-serial=rtt` for serial output over SWD
|
||||||
|
* add Go 1.22 support and use it by default
|
||||||
|
* change minimum Node.js version from 16 to 18
|
||||||
|
* **compiler**
|
||||||
|
* use the new LLVM pass manager
|
||||||
|
* allow systems with more stack space to allocate larger values on the stack
|
||||||
|
* `build`: fix a crash due to sharing GlobalValues between build instances
|
||||||
|
* `cgo`: add `C._Bool` type
|
||||||
|
* `cgo`: fix calling CGo callback inside generic function
|
||||||
|
* `compileopts`: set `purego` build tag by default so that more packages can be built
|
||||||
|
* `compileopts`: force-enable CGo to avoid build issues
|
||||||
|
* `compiler`: fix crash on type assert on interfaces with no methods
|
||||||
|
* `interp`: print LLVM instruction in traceback
|
||||||
|
* `interp`: support runtime times by running them at runtime
|
||||||
|
* `loader`: enforce Go language version in the type checker (this may break existing programs with an incorrect Go version in go.mod)
|
||||||
|
* `transform`: fix bug in StringToBytes optimization pass
|
||||||
|
* **standard library**
|
||||||
|
* `crypto/tls`: stub out a lot of functions
|
||||||
|
* `internal/task`, `machine`: make TinyGo code usable with "big Go" CGo
|
||||||
|
* `machine`: implement `I2C.SetBaudRate` consistently across chips
|
||||||
|
* `machine`: implement `SPI.Configure` consistently across chips
|
||||||
|
* `machine`: add `DeviceID` for nrf, rp2040, sam, stm32
|
||||||
|
* `machine`: use smaller UART buffer size on atmega chips
|
||||||
|
* `machine/usb`: allow setting a serial number using a linker flag
|
||||||
|
* `math`: support more math functions on baremetal (picolibc) systems
|
||||||
|
* `net`: replace entire net package with a new one based on the netdev driver
|
||||||
|
* `os/user`: add bare-bones implementation of this package
|
||||||
|
* `reflect`: stub `CallSlice` and `FuncOf`
|
||||||
|
* `reflect`: add `TypeFor[T]`
|
||||||
|
* `reflect`: update `IsZero` to Go 1.22 semantics
|
||||||
|
* `reflect`: move indirect values into interface when setting interfaces
|
||||||
|
* `runtime`: stub `Breakpoint`
|
||||||
|
* `sync`: implement trylock
|
||||||
|
* **targets**
|
||||||
|
* `atmega`: use UART double speed mode for fewer errors and higher throughput
|
||||||
|
* `atmega328pb`: refactor to enable extra uart
|
||||||
|
* `avr`: don't compile large parts of picolibc (math, stdio) for LLVM 17 support
|
||||||
|
* `esp32`: switch over to the official SVD file
|
||||||
|
* `esp32c3`: implement USB_SERIAL for USBCDC communication
|
||||||
|
* `esp32c3`: implement I2C
|
||||||
|
* `esp32c3`: implement RNG
|
||||||
|
* `esp32c3`: add more ROM functions and update linker script for the in-progress wifi support
|
||||||
|
* `esp32c3`: update to newer SVD files
|
||||||
|
* `rp2040`: add support for UART hardware flow control
|
||||||
|
* `rp2040`: add definition for `machine.PinToggle`
|
||||||
|
* `rp2040`: set XOSC startup delay multiplier
|
||||||
|
* `samd21`: add support for UART hardware flow control
|
||||||
|
* `samd51`: add support for UART hardware flow control
|
||||||
|
* `wasm`: increase default stack size to 64k for wasi/wasm targets
|
||||||
|
* `wasm`: bump wasi-libc version to SDK 20
|
||||||
|
* `wasm`: remove line of dead code in wasm_exec.js
|
||||||
|
* **new targets/boards**
|
||||||
|
* `qtpy-esp32c3`: add Adafruit QT Py ESP32-C3 board
|
||||||
|
* `mksnanov3`: add support for the MKS Robin Nano V3.x
|
||||||
|
* `nrf52840-generic`: add generic nrf52840 chip support
|
||||||
|
* `thumby`: add support for Thumby
|
||||||
|
* `wasm`: add new `wasm-unknown` target that doesn't depend on WASI or a browser
|
||||||
|
* **boards**
|
||||||
|
* `arduino-mkrwifi1010`, `arduino-nano33`, `nano-rp2040`, `matrixportal-m4`, `metro-m4-airlift`, `pybadge`, `pyportal`: add `ninafw` build tag and some constants for BLE support
|
||||||
|
* `gopher-badge`: fix typo in USB product name
|
||||||
|
* `nano-rp2040`: add UART1 and correct mappings for NINA via UART
|
||||||
|
* `pico`: bump default stack size from 2kB to 8kB
|
||||||
|
* `wioterminal`: expose UART4
|
||||||
|
|
||||||
|
|
||||||
0.30.0
|
0.30.0
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+22
-19
@@ -1,10 +1,15 @@
|
|||||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||||
FROM golang:1.21 AS tinygo-llvm
|
FROM golang:1.22 AS tinygo-llvm
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
apt-get install -y apt-utils make cmake clang-15 ninja-build
|
apt-get install -y apt-utils make cmake clang-15 ninja-build && \
|
||||||
|
rm -rf \
|
||||||
|
/var/lib/apt/lists/* \
|
||||||
|
/var/log/* \
|
||||||
|
/var/tmp/* \
|
||||||
|
/tmp/*
|
||||||
|
|
||||||
COPY ./Makefile /tinygo/Makefile
|
COPY ./GNUmakefile /tinygo/GNUmakefile
|
||||||
|
|
||||||
RUN cd /tinygo/ && \
|
RUN cd /tinygo/ && \
|
||||||
make llvm-source
|
make llvm-source
|
||||||
@@ -15,26 +20,24 @@ FROM tinygo-llvm AS tinygo-llvm-build
|
|||||||
RUN cd /tinygo/ && \
|
RUN cd /tinygo/ && \
|
||||||
make llvm-build
|
make llvm-build
|
||||||
|
|
||||||
# tinygo-compiler stage builds the compiler itself
|
# tinygo-compiler-build stage builds the compiler itself
|
||||||
FROM tinygo-llvm-build AS tinygo-compiler
|
FROM tinygo-llvm-build AS tinygo-compiler-build
|
||||||
|
|
||||||
COPY . /tinygo
|
COPY . /tinygo
|
||||||
|
|
||||||
# update submodules
|
# build the compiler and tools
|
||||||
RUN cd /tinygo/ && \
|
RUN cd /tinygo/ && \
|
||||||
rm -rf ./lib/*/ && \
|
git submodule update --init --recursive && \
|
||||||
git submodule sync && \
|
|
||||||
git submodule update --init --recursive --force
|
|
||||||
|
|
||||||
RUN cd /tinygo/ && \
|
|
||||||
make
|
|
||||||
|
|
||||||
# tinygo-tools stage installs the needed dependencies to compile TinyGo programs for all platforms.
|
|
||||||
FROM tinygo-compiler AS tinygo-tools
|
|
||||||
|
|
||||||
RUN cd /tinygo/ && \
|
|
||||||
make wasi-libc binaryen && \
|
|
||||||
make gen-device -j4 && \
|
make gen-device -j4 && \
|
||||||
cp build/* $GOPATH/bin/
|
make build/release
|
||||||
|
|
||||||
|
# tinygo-compiler copies the compiler build over to a base Go container (without
|
||||||
|
# all the build tools etc).
|
||||||
|
FROM golang:1.22 AS tinygo-compiler
|
||||||
|
|
||||||
|
# Copy tinygo build.
|
||||||
|
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
|
||||||
|
|
||||||
|
# Configure the container.
|
||||||
|
ENV PATH="${PATH}:/tinygo/bin"
|
||||||
CMD ["tinygo"]
|
CMD ["tinygo"]
|
||||||
|
|||||||
+18
-8
@@ -238,7 +238,7 @@ gen-device-renesas: build/gen-device-svd
|
|||||||
|
|
||||||
# Get LLVM sources.
|
# Get LLVM sources.
|
||||||
$(LLVM_PROJECTDIR)/llvm:
|
$(LLVM_PROJECTDIR)/llvm:
|
||||||
git clone -b xtensa_release_16.x --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
|
git clone -b xtensa_release_17.0.1 --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
|
||||||
llvm-source: $(LLVM_PROJECTDIR)/llvm
|
llvm-source: $(LLVM_PROJECTDIR)/llvm
|
||||||
|
|
||||||
# Configure LLVM.
|
# Configure LLVM.
|
||||||
@@ -256,7 +256,7 @@ ifneq ($(USE_SYSTEM_BINARYEN),1)
|
|||||||
binaryen: build/wasm-opt$(EXE)
|
binaryen: build/wasm-opt$(EXE)
|
||||||
build/wasm-opt$(EXE):
|
build/wasm-opt$(EXE):
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd lib/binaryen && cmake -G Ninja . -DBUILD_STATIC_LIB=ON $(BINARYEN_OPTION) && ninja bin/wasm-opt$(EXE)
|
cd lib/binaryen && cmake -G Ninja . -DBUILD_STATIC_LIB=ON -DBUILD_TESTS=OFF $(BINARYEN_OPTION) && ninja bin/wasm-opt$(EXE)
|
||||||
cp lib/binaryen/bin/wasm-opt$(EXE) build/wasm-opt$(EXE)
|
cp lib/binaryen/bin/wasm-opt$(EXE) build/wasm-opt$(EXE)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -269,14 +269,14 @@ lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
|
|||||||
|
|
||||||
# Check for Node.js used during WASM tests.
|
# Check for Node.js used during WASM tests.
|
||||||
NODEJS_VERSION := $(word 1,$(subst ., ,$(shell node -v | cut -c 2-)))
|
NODEJS_VERSION := $(word 1,$(subst ., ,$(shell node -v | cut -c 2-)))
|
||||||
MIN_NODEJS_VERSION=16
|
MIN_NODEJS_VERSION=18
|
||||||
|
|
||||||
.PHONY: check-nodejs-version
|
.PHONY: check-nodejs-version
|
||||||
check-nodejs-version:
|
check-nodejs-version:
|
||||||
ifeq (, $(shell which node))
|
ifeq (, $(shell which node))
|
||||||
@echo "Install NodeJS version 16+ to run tests."; exit 1;
|
@echo "Install NodeJS version 18+ to run tests."; exit 1;
|
||||||
endif
|
endif
|
||||||
@if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 16+ to run tests."; exit 1; fi
|
@if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 18+ to run tests."; exit 1; fi
|
||||||
|
|
||||||
# Build the Go compiler.
|
# Build the Go compiler.
|
||||||
tinygo:
|
tinygo:
|
||||||
@@ -670,6 +670,8 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
|
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=thumby examples/echo
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
# test pwm
|
# test pwm
|
||||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
@@ -684,6 +686,8 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/usb-midi
|
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/usb-midi
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=nrf52840-s140v6-uf2-generic examples/serial
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
ifneq ($(STM32), 0)
|
ifneq ($(STM32), 0)
|
||||||
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
@@ -717,7 +721,11 @@ ifneq ($(STM32), 0)
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=swan examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=swan examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=mksnanov3 examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
endif
|
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/serial
|
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
|
||||||
@@ -754,9 +762,7 @@ ifneq ($(XTENSA), 0)
|
|||||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/serial
|
$(TINYGO) build -size short -o test.bin -target mch2022 examples/serial
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
endif
|
endif
|
||||||
$(TINYGO) build -size short -o test.bin -target=esp32c3 examples/serial
|
$(TINYGO) build -size short -o test.bin -target=qtpy-esp32c3 examples/serial
|
||||||
@$(MD5SUM) test.bin
|
|
||||||
$(TINYGO) build -size short -o test.bin -target=esp32c3-12f examples/serial
|
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/serial
|
$(TINYGO) build -size short -o test.bin -target=m5stamp-c3 examples/serial
|
||||||
@$(MD5SUM) test.bin
|
@$(MD5SUM) test.bin
|
||||||
@@ -769,6 +775,7 @@ endif
|
|||||||
ifneq ($(WASM), 0)
|
ifneq ($(WASM), 0)
|
||||||
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
|
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
|
||||||
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
|
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
|
||||||
|
$(TINYGO) build -size short -o wasm.wasm -target=wasm-unknown examples/hello-wasm-unknown
|
||||||
endif
|
endif
|
||||||
# test various compiler flags
|
# test various compiler flags
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -gc=none -scheduler=none examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=pca10040 -gc=none -scheduler=none examples/blinky1
|
||||||
@@ -777,6 +784,8 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=none examples/echo
|
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=none examples/echo
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=rtt examples/echo
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
|
$(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
|
||||||
@$(MD5SUM) test.nro
|
@$(MD5SUM) test.nro
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
|
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
|
||||||
@@ -836,6 +845,7 @@ endif
|
|||||||
@cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/include build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/internal build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/legacy build/release/tinygo/lib/musl/src
|
||||||
|
@cp -rp lib/musl/src/linux build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/malloc build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/mman build/release/tinygo/lib/musl/src
|
||||||
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
|
@cp -rp lib/musl/src/math build/release/tinygo/lib/musl/src
|
||||||
|
|||||||
+3
-15
@@ -197,6 +197,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
Scheduler: config.Scheduler(),
|
Scheduler: config.Scheduler(),
|
||||||
AutomaticStackSize: config.AutomaticStackSize(),
|
AutomaticStackSize: config.AutomaticStackSize(),
|
||||||
DefaultStackSize: config.StackSize(),
|
DefaultStackSize: config.StackSize(),
|
||||||
|
MaxStackAlloc: config.MaxStackAlloc(),
|
||||||
NeedsStackObjects: config.NeedsStackObjects(),
|
NeedsStackObjects: config.NeedsStackObjects(),
|
||||||
Debug: !config.Options.SkipDWARF, // emit DWARF except when -internal-nodwarf is passed
|
Debug: !config.Options.SkipDWARF, // emit DWARF except when -internal-nodwarf is passed
|
||||||
}
|
}
|
||||||
@@ -807,21 +808,8 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
|||||||
|
|
||||||
// Run wasm-opt for wasm binaries
|
// Run wasm-opt for wasm binaries
|
||||||
if arch := strings.Split(config.Triple(), "-")[0]; arch == "wasm32" {
|
if arch := strings.Split(config.Triple(), "-")[0]; arch == "wasm32" {
|
||||||
var opt string
|
optLevel, _, _ := config.OptLevel()
|
||||||
switch config.Options.Opt {
|
opt := "-" + optLevel
|
||||||
case "none", "0":
|
|
||||||
opt = "-O0"
|
|
||||||
case "1":
|
|
||||||
opt = "-O1"
|
|
||||||
case "2":
|
|
||||||
opt = "-O2"
|
|
||||||
case "s":
|
|
||||||
opt = "-Os"
|
|
||||||
case "z":
|
|
||||||
opt = "-Oz"
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown opt level: %q", config.Options.Opt)
|
|
||||||
}
|
|
||||||
|
|
||||||
var args []string
|
var args []string
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ func TestClangAttributes(t *testing.T) {
|
|||||||
"riscv-qemu",
|
"riscv-qemu",
|
||||||
"wasi",
|
"wasi",
|
||||||
"wasm",
|
"wasm",
|
||||||
|
"wasm-unknown",
|
||||||
}
|
}
|
||||||
if hasBuiltinTools {
|
if hasBuiltinTools {
|
||||||
// hasBuiltinTools is set when TinyGo is statically linked with LLVM,
|
// hasBuiltinTools is set when TinyGo is statically linked with LLVM,
|
||||||
|
|||||||
+17
-6
@@ -1,5 +1,12 @@
|
|||||||
//go:build byollvm
|
//go:build byollvm
|
||||||
|
|
||||||
|
// Source: https://github.com/llvm/llvm-project/blob/main/clang/tools/driver/cc1as_main.cpp
|
||||||
|
// This file needs to be updated each LLVM release.
|
||||||
|
// There are a few small modifications to make, like:
|
||||||
|
// * ExecuteAssembler is made non-static.
|
||||||
|
// * The struct AssemblerImplementation is moved to cc1as.h so it can be
|
||||||
|
// included elsewhere.
|
||||||
|
|
||||||
//===-- cc1as.cpp - Clang Assembler --------------------------------------===//
|
//===-- cc1as.cpp - Clang Assembler --------------------------------------===//
|
||||||
//
|
//
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
@@ -21,8 +28,8 @@
|
|||||||
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
#include "clang/Frontend/TextDiagnosticPrinter.h"
|
||||||
#include "clang/Frontend/Utils.h"
|
#include "clang/Frontend/Utils.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
|
#include "llvm/ADT/StringExtras.h"
|
||||||
#include "llvm/ADT/StringSwitch.h"
|
#include "llvm/ADT/StringSwitch.h"
|
||||||
#include "llvm/ADT/Triple.h"
|
|
||||||
#include "llvm/IR/DataLayout.h"
|
#include "llvm/IR/DataLayout.h"
|
||||||
#include "llvm/MC/MCAsmBackend.h"
|
#include "llvm/MC/MCAsmBackend.h"
|
||||||
#include "llvm/MC/MCAsmInfo.h"
|
#include "llvm/MC/MCAsmInfo.h"
|
||||||
@@ -46,7 +53,6 @@
|
|||||||
#include "llvm/Support/ErrorHandling.h"
|
#include "llvm/Support/ErrorHandling.h"
|
||||||
#include "llvm/Support/FileSystem.h"
|
#include "llvm/Support/FileSystem.h"
|
||||||
#include "llvm/Support/FormattedStream.h"
|
#include "llvm/Support/FormattedStream.h"
|
||||||
#include "llvm/Support/Host.h"
|
|
||||||
#include "llvm/Support/MemoryBuffer.h"
|
#include "llvm/Support/MemoryBuffer.h"
|
||||||
#include "llvm/Support/Path.h"
|
#include "llvm/Support/Path.h"
|
||||||
#include "llvm/Support/Process.h"
|
#include "llvm/Support/Process.h"
|
||||||
@@ -55,6 +61,8 @@
|
|||||||
#include "llvm/Support/TargetSelect.h"
|
#include "llvm/Support/TargetSelect.h"
|
||||||
#include "llvm/Support/Timer.h"
|
#include "llvm/Support/Timer.h"
|
||||||
#include "llvm/Support/raw_ostream.h"
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
#include "llvm/TargetParser/Host.h"
|
||||||
|
#include "llvm/TargetParser/Triple.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
@@ -151,8 +159,7 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
|||||||
|
|
||||||
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
|
for (const auto &Arg : Args.getAllArgValues(OPT_fdebug_prefix_map_EQ)) {
|
||||||
auto Split = StringRef(Arg).split('=');
|
auto Split = StringRef(Arg).split('=');
|
||||||
Opts.DebugPrefixMap.insert(
|
Opts.DebugPrefixMap.emplace_back(Split.first, Split.second);
|
||||||
{std::string(Split.first), std::string(Split.second)});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Frontend Options
|
// Frontend Options
|
||||||
@@ -225,6 +232,9 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
|||||||
.Case("default", EmitDwarfUnwindType::Default);
|
.Case("default", EmitDwarfUnwindType::Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Opts.EmitCompactUnwindNonCanonical =
|
||||||
|
Args.hasArg(OPT_femit_compact_unwind_non_canonical);
|
||||||
|
|
||||||
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
|
Opts.AsSecureLogFile = Args.getLastArgValue(OPT_as_secure_log_file);
|
||||||
|
|
||||||
return Success;
|
return Success;
|
||||||
@@ -260,8 +270,8 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
|||||||
MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
|
MemoryBuffer::getFileOrSTDIN(Opts.InputFile, /*IsText=*/true);
|
||||||
|
|
||||||
if (std::error_code EC = Buffer.getError()) {
|
if (std::error_code EC = Buffer.getError()) {
|
||||||
Error = EC.message();
|
return Diags.Report(diag::err_fe_error_reading)
|
||||||
return Diags.Report(diag::err_fe_error_reading) << Opts.InputFile;
|
<< Opts.InputFile << EC.message();
|
||||||
}
|
}
|
||||||
|
|
||||||
SourceMgr SrcMgr;
|
SourceMgr SrcMgr;
|
||||||
@@ -278,6 +288,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
|||||||
|
|
||||||
MCTargetOptions MCOptions;
|
MCTargetOptions MCOptions;
|
||||||
MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
|
MCOptions.EmitDwarfUnwind = Opts.EmitDwarfUnwind;
|
||||||
|
MCOptions.EmitCompactUnwindNonCanonical = Opts.EmitCompactUnwindNonCanonical;
|
||||||
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
|
MCOptions.AsSecureLogFile = Opts.AsSecureLogFile;
|
||||||
|
|
||||||
std::unique_ptr<MCAsmInfo> MAI(
|
std::unique_ptr<MCAsmInfo> MAI(
|
||||||
|
|||||||
+9
-1
@@ -1,3 +1,6 @@
|
|||||||
|
// Source: https://github.com/llvm/llvm-project/blob/main/clang/tools/driver/cc1as_main.cpp
|
||||||
|
// See cc1as.cpp for details.
|
||||||
|
|
||||||
//===-- cc1as.h - Clang Assembler ----------------------------------------===//
|
//===-- cc1as.h - Clang Assembler ----------------------------------------===//
|
||||||
//
|
//
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
@@ -44,7 +47,7 @@ struct AssemblerInvocation {
|
|||||||
std::string DwarfDebugFlags;
|
std::string DwarfDebugFlags;
|
||||||
std::string DwarfDebugProducer;
|
std::string DwarfDebugProducer;
|
||||||
std::string DebugCompilationDir;
|
std::string DebugCompilationDir;
|
||||||
std::map<const std::string, const std::string> DebugPrefixMap;
|
llvm::SmallVector<std::pair<std::string, std::string>, 0> DebugPrefixMap;
|
||||||
llvm::DebugCompressionType CompressDebugSections =
|
llvm::DebugCompressionType CompressDebugSections =
|
||||||
llvm::DebugCompressionType::None;
|
llvm::DebugCompressionType::None;
|
||||||
std::string MainFileName;
|
std::string MainFileName;
|
||||||
@@ -89,6 +92,10 @@ struct AssemblerInvocation {
|
|||||||
/// Whether to emit DWARF unwind info.
|
/// Whether to emit DWARF unwind info.
|
||||||
EmitDwarfUnwindType EmitDwarfUnwind;
|
EmitDwarfUnwindType EmitDwarfUnwind;
|
||||||
|
|
||||||
|
// Whether to emit compact-unwind for non-canonical entries.
|
||||||
|
// Note: maybe overriden by other constraints.
|
||||||
|
unsigned EmitCompactUnwindNonCanonical : 1;
|
||||||
|
|
||||||
/// The name of the relocation model to use.
|
/// The name of the relocation model to use.
|
||||||
std::string RelocationModel;
|
std::string RelocationModel;
|
||||||
|
|
||||||
@@ -128,6 +135,7 @@ public:
|
|||||||
DwarfVersion = 0;
|
DwarfVersion = 0;
|
||||||
EmbedBitcode = 0;
|
EmbedBitcode = 0;
|
||||||
EmitDwarfUnwind = EmitDwarfUnwindType::Default;
|
EmitDwarfUnwind = EmitDwarfUnwindType::Default;
|
||||||
|
EmitCompactUnwindNonCanonical = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool CreateFromArgs(AssemblerInvocation &Res,
|
static bool CreateFromArgs(AssemblerInvocation &Res,
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@
|
|||||||
#include <clang/FrontendTool/Utils.h>
|
#include <clang/FrontendTool/Utils.h>
|
||||||
#include <llvm/ADT/IntrusiveRefCntPtr.h>
|
#include <llvm/ADT/IntrusiveRefCntPtr.h>
|
||||||
#include <llvm/Option/Option.h>
|
#include <llvm/Option/Option.h>
|
||||||
#include <llvm/Support/Host.h>
|
#include <llvm/TargetParser/Host.h>
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
|||||||
+2
-2
@@ -27,10 +27,10 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if major != 1 || minor < 18 || minor > 21 {
|
if major != 1 || minor < 18 || minor > 22 {
|
||||||
// Note: when this gets updated, also update the Go compatibility matrix:
|
// Note: when this gets updated, also update the Go compatibility matrix:
|
||||||
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
||||||
return nil, fmt.Errorf("requires go version 1.18 through 1.21, got go%d.%d", major, minor)
|
return nil, fmt.Errorf("requires go version 1.18 through 1.22, got go%d.%d", major, minor)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &compileopts.Config{
|
return &compileopts.Config{
|
||||||
|
|||||||
+9
-20
@@ -5,7 +5,11 @@
|
|||||||
#include <lld/Common/Driver.h>
|
#include <lld/Common/Driver.h>
|
||||||
#include <llvm/Support/Parallel.h>
|
#include <llvm/Support/Parallel.h>
|
||||||
|
|
||||||
extern "C" {
|
LLD_HAS_DRIVER(coff)
|
||||||
|
LLD_HAS_DRIVER(elf)
|
||||||
|
LLD_HAS_DRIVER(mingw)
|
||||||
|
LLD_HAS_DRIVER(macho)
|
||||||
|
LLD_HAS_DRIVER(wasm)
|
||||||
|
|
||||||
static void configure() {
|
static void configure() {
|
||||||
#if _WIN64
|
#if _WIN64
|
||||||
@@ -16,28 +20,13 @@ static void configure() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tinygo_link_elf(int argc, char **argv) {
|
extern "C" {
|
||||||
configure();
|
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
|
||||||
return lld::elf::link(args, llvm::outs(), llvm::errs(), false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tinygo_link_macho(int argc, char **argv) {
|
bool tinygo_link(int argc, char **argv) {
|
||||||
configure();
|
configure();
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
std::vector<const char*> args(argv, argv + argc);
|
||||||
return lld::macho::link(args, llvm::outs(), llvm::errs(), false, false);
|
lld::Result r = lld::lldMain(args, llvm::outs(), llvm::errs(), LLD_ALL_DRIVERS);
|
||||||
}
|
return !r.retCode;
|
||||||
|
|
||||||
bool tinygo_link_mingw(int argc, char **argv) {
|
|
||||||
configure();
|
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
|
||||||
return lld::mingw::link(args, llvm::outs(), llvm::errs(), false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tinygo_link_wasm(int argc, char **argv) {
|
|
||||||
configure();
|
|
||||||
std::vector<const char*> args(argv, argv + argc);
|
|
||||||
return lld::wasm::link(args, llvm::outs(), llvm::errs(), false, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // external "C"
|
} // external "C"
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ var Musl = Library{
|
|||||||
"internal/syscall_ret.c",
|
"internal/syscall_ret.c",
|
||||||
"internal/vdso.c",
|
"internal/vdso.c",
|
||||||
"legacy/*.c",
|
"legacy/*.c",
|
||||||
|
"linux/*.c",
|
||||||
"malloc/*.c",
|
"malloc/*.c",
|
||||||
"malloc/mallocng/*.c",
|
"malloc/mallocng/*.c",
|
||||||
"mman/*.c",
|
"mman/*.c",
|
||||||
|
|||||||
@@ -337,6 +337,12 @@ var picolibcSourcesLarge = []string{
|
|||||||
"libm/common/math_err_may_uflow.c",
|
"libm/common/math_err_may_uflow.c",
|
||||||
"libm/common/math_err_check_uflow.c",
|
"libm/common/math_err_check_uflow.c",
|
||||||
"libm/common/math_err_check_oflow.c",
|
"libm/common/math_err_check_oflow.c",
|
||||||
|
"libm/common/math_errf_divzerof.c",
|
||||||
|
"libm/common/math_errf_invalidf.c",
|
||||||
|
"libm/common/math_errf_may_uflowf.c",
|
||||||
|
"libm/common/math_errf_oflowf.c",
|
||||||
|
"libm/common/math_errf_uflowf.c",
|
||||||
|
"libm/common/math_errf_with_errnof.c",
|
||||||
"libm/common/math_inexact.c",
|
"libm/common/math_inexact.c",
|
||||||
"libm/common/math_inexactf.c",
|
"libm/common/math_inexactf.c",
|
||||||
"libm/common/log.c",
|
"libm/common/log.c",
|
||||||
|
|||||||
@@ -41,9 +41,9 @@ func TestBinarySize(t *testing.T) {
|
|||||||
// This is a small number of very diverse targets that we want to test.
|
// This is a small number of very diverse targets that we want to test.
|
||||||
tests := []sizeTest{
|
tests := []sizeTest{
|
||||||
// microcontrollers
|
// microcontrollers
|
||||||
{"hifive1b", "examples/echo", 4484, 280, 0, 2252},
|
{"hifive1b", "examples/echo", 4476, 280, 0, 2252},
|
||||||
{"microbit", "examples/serial", 2724, 388, 8, 2256},
|
{"microbit", "examples/serial", 2724, 388, 8, 2256},
|
||||||
{"wioterminal", "examples/pininterrupt", 6000, 1484, 116, 6816},
|
{"wioterminal", "examples/pininterrupt", 5996, 1484, 116, 6816},
|
||||||
|
|
||||||
// TODO: also check wasm. Right now this is difficult, because
|
// TODO: also check wasm. Right now this is difficult, because
|
||||||
// wasm binaries are run through wasm-opt and therefore the
|
// wasm binaries are run through wasm-opt and therefore the
|
||||||
|
|||||||
@@ -12,10 +12,7 @@ import (
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
bool tinygo_clang_driver(int argc, char **argv);
|
bool tinygo_clang_driver(int argc, char **argv);
|
||||||
bool tinygo_link_elf(int argc, char **argv);
|
bool tinygo_link(int argc, char **argv);
|
||||||
bool tinygo_link_macho(int argc, char **argv);
|
|
||||||
bool tinygo_link_mingw(int argc, char **argv);
|
|
||||||
bool tinygo_link_wasm(int argc, char **argv);
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
@@ -26,16 +23,7 @@ const hasBuiltinTools = true
|
|||||||
// This version actually runs the tools because TinyGo was compiled while
|
// This version actually runs the tools because TinyGo was compiled while
|
||||||
// linking statically with LLVM (with the byollvm build tag).
|
// linking statically with LLVM (with the byollvm build tag).
|
||||||
func RunTool(tool string, args ...string) error {
|
func RunTool(tool string, args ...string) error {
|
||||||
linker := "elf"
|
args = append([]string{tool}, args...)
|
||||||
if tool == "ld.lld" && len(args) >= 2 {
|
|
||||||
if args[0] == "-m" && (args[1] == "i386pep" || args[1] == "arm64pe") {
|
|
||||||
linker = "mingw"
|
|
||||||
} else if args[0] == "-flavor" {
|
|
||||||
linker = args[1]
|
|
||||||
args = args[2:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
args = append([]string{"tinygo:" + tool}, args...)
|
|
||||||
|
|
||||||
var cflag *C.char
|
var cflag *C.char
|
||||||
buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag)))
|
buf := C.calloc(C.size_t(len(args)), C.size_t(unsafe.Sizeof(cflag)))
|
||||||
@@ -51,19 +39,8 @@ func RunTool(tool string, args ...string) error {
|
|||||||
switch tool {
|
switch tool {
|
||||||
case "clang":
|
case "clang":
|
||||||
ok = C.tinygo_clang_driver(C.int(len(args)), (**C.char)(buf))
|
ok = C.tinygo_clang_driver(C.int(len(args)), (**C.char)(buf))
|
||||||
case "ld.lld":
|
case "ld.lld", "wasm-ld":
|
||||||
switch linker {
|
ok = C.tinygo_link(C.int(len(args)), (**C.char)(buf))
|
||||||
case "darwin":
|
|
||||||
ok = C.tinygo_link_macho(C.int(len(args)), (**C.char)(buf))
|
|
||||||
case "elf":
|
|
||||||
ok = C.tinygo_link_elf(C.int(len(args)), (**C.char)(buf))
|
|
||||||
case "mingw":
|
|
||||||
ok = C.tinygo_link_mingw(C.int(len(args)), (**C.char)(buf))
|
|
||||||
default:
|
|
||||||
return errors.New("unknown linker: " + linker)
|
|
||||||
}
|
|
||||||
case "wasm-ld":
|
|
||||||
ok = C.tinygo_link_wasm(C.int(len(args)), (**C.char)(buf))
|
|
||||||
default:
|
default:
|
||||||
return errors.New("unknown tool: " + tool)
|
return errors.New("unknown tool: " + tool)
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-2
@@ -25,9 +25,15 @@ import (
|
|||||||
"golang.org/x/tools/go/ast/astutil"
|
"golang.org/x/tools/go/ast/astutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Function that's only defined in Go 1.22.
|
||||||
|
var setASTFileFields = func(f *ast.File, start, end token.Pos) {
|
||||||
|
}
|
||||||
|
|
||||||
// cgoPackage holds all CGo-related information of a package.
|
// cgoPackage holds all CGo-related information of a package.
|
||||||
type cgoPackage struct {
|
type cgoPackage struct {
|
||||||
generated *ast.File
|
generated *ast.File
|
||||||
|
packageName string
|
||||||
|
cgoFiles []*ast.File
|
||||||
generatedPos token.Pos
|
generatedPos token.Pos
|
||||||
errors []error
|
errors []error
|
||||||
currentDir string // current working directory
|
currentDir string // current working directory
|
||||||
@@ -165,8 +171,9 @@ func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
|||||||
// functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
|
// functions), the CFLAGS and LDFLAGS found in #cgo lines, and a map of file
|
||||||
// hashes of the accessed C header files. If there is one or more error, it
|
// hashes of the accessed C header files. If there is one or more error, it
|
||||||
// returns these in the []error slice but still modifies the AST.
|
// returns these in the []error slice but still modifies the AST.
|
||||||
func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cflags []string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cflags []string) ([]*ast.File, []string, []string, []string, map[string][]byte, []error) {
|
||||||
p := &cgoPackage{
|
p := &cgoPackage{
|
||||||
|
packageName: files[0].Name.Name,
|
||||||
currentDir: dir,
|
currentDir: dir,
|
||||||
importPath: importPath,
|
importPath: importPath,
|
||||||
fset: fset,
|
fset: fset,
|
||||||
@@ -202,6 +209,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
|||||||
// This is always a bug in the cgo package.
|
// This is always a bug in the cgo package.
|
||||||
panic("unexpected error: " + err.Error())
|
panic("unexpected error: " + err.Error())
|
||||||
}
|
}
|
||||||
|
p.cgoFiles = append(p.cgoFiles, p.generated)
|
||||||
// If the Comments field is not set to nil, the go/format package will get
|
// If the Comments field is not set to nil, the go/format package will get
|
||||||
// confused about where comments should go.
|
// confused about where comments should go.
|
||||||
p.generated.Comments = nil
|
p.generated.Comments = nil
|
||||||
@@ -332,7 +340,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
|||||||
// Print the newly generated in-memory AST, for debugging.
|
// Print the newly generated in-memory AST, for debugging.
|
||||||
//ast.Print(fset, p.generated)
|
//ast.Print(fset, p.generated)
|
||||||
|
|
||||||
return p.generated, p.cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
|
return p.cgoFiles, p.cgoHeaders, p.cflags, p.ldflags, p.visitedFiles, p.errors
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *cgoPackage) newCGoFile(file *ast.File, index int) *cgoFile {
|
func (p *cgoPackage) newCGoFile(file *ast.File, index int) *cgoFile {
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
//go:build go1.22
|
||||||
|
|
||||||
|
package cgo
|
||||||
|
|
||||||
|
// Code specifically for Go 1.22.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
"go/token"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
setASTFileFields = func(f *ast.File, start, end token.Pos) {
|
||||||
|
f.FileStart = start
|
||||||
|
f.FileEnd = end
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
-3
@@ -55,7 +55,7 @@ func TestCGo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process the AST with CGo.
|
// Process the AST with CGo.
|
||||||
cgoAST, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags)
|
cgoFiles, _, _, _, _, cgoErrors := Process([]*ast.File{f}, "testdata", "main", fset, cflags)
|
||||||
|
|
||||||
// Check the AST for type errors.
|
// Check the AST for type errors.
|
||||||
var typecheckErrors []error
|
var typecheckErrors []error
|
||||||
@@ -66,7 +66,7 @@ func TestCGo(t *testing.T) {
|
|||||||
Importer: simpleImporter{},
|
Importer: simpleImporter{},
|
||||||
Sizes: types.SizesFor("gccgo", "arm"),
|
Sizes: types.SizesFor("gccgo", "arm"),
|
||||||
}
|
}
|
||||||
_, err = config.Check("", fset, []*ast.File{f, cgoAST}, nil)
|
_, err = config.Check("", fset, append([]*ast.File{f}, cgoFiles...), nil)
|
||||||
if err != nil && len(typecheckErrors) == 0 {
|
if err != nil && len(typecheckErrors) == 0 {
|
||||||
// Only report errors when no type errors are found (an
|
// Only report errors when no type errors are found (an
|
||||||
// unexpected condition).
|
// unexpected condition).
|
||||||
@@ -91,7 +91,7 @@ func TestCGo(t *testing.T) {
|
|||||||
}
|
}
|
||||||
buf.WriteString("\n")
|
buf.WriteString("\n")
|
||||||
}
|
}
|
||||||
err = format.Node(buf, fset, cgoAST)
|
err = format.Node(buf, fset, cgoFiles[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("could not write out CGo AST: %v", err)
|
t.Errorf("could not write out CGo AST: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -589,6 +589,13 @@ func (p *cgoPackage) getClangLocationPosition(location C.CXSourceLocation, tu C.
|
|||||||
f := p.fset.AddFile(filename, -1, int(size))
|
f := p.fset.AddFile(filename, -1, int(size))
|
||||||
f.SetLines(lines)
|
f.SetLines(lines)
|
||||||
p.tokenFiles[filename] = f
|
p.tokenFiles[filename] = f
|
||||||
|
// Add dummy file AST, to satisfy the type checker.
|
||||||
|
astFile := &ast.File{
|
||||||
|
Package: f.Pos(0),
|
||||||
|
Name: ast.NewIdent(p.packageName),
|
||||||
|
}
|
||||||
|
setASTFileFields(astFile, f.Pos(0), f.Pos(int(size)))
|
||||||
|
p.cgoFiles = append(p.cgoFiles, astFile)
|
||||||
}
|
}
|
||||||
positionFile := p.tokenFiles[filename]
|
positionFile := p.tokenFiles[filename]
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !byollvm && !llvm15 && !llvm17
|
//go:build !byollvm && llvm16
|
||||||
|
|
||||||
package cgo
|
package cgo
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build !byollvm && llvm17
|
//go:build !byollvm && !llvm15 && !llvm16
|
||||||
|
|
||||||
package cgo
|
package cgo
|
||||||
|
|
||||||
|
|||||||
+15
-11
@@ -74,7 +74,12 @@ func (c *Config) GOARM() string {
|
|||||||
|
|
||||||
// BuildTags returns the complete list of build tags used during this build.
|
// BuildTags returns the complete list of build tags used during this build.
|
||||||
func (c *Config) BuildTags() []string {
|
func (c *Config) BuildTags() []string {
|
||||||
tags := append(c.Target.BuildTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
|
tags := append(c.Target.BuildTags, []string{
|
||||||
|
"tinygo", // that's the compiler
|
||||||
|
"purego", // to get various crypto packages to work
|
||||||
|
"math_big_pure_go", // to get math/big to work
|
||||||
|
"gc." + c.GC(), "scheduler." + c.Scheduler(), // used inside the runtime package
|
||||||
|
"serial." + c.Serial()}...) // used inside the machine package
|
||||||
for i := 1; i <= c.GoMinorVersion; i++ {
|
for i := 1; i <= c.GoMinorVersion; i++ {
|
||||||
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
||||||
}
|
}
|
||||||
@@ -82,12 +87,6 @@ func (c *Config) BuildTags() []string {
|
|||||||
return tags
|
return tags
|
||||||
}
|
}
|
||||||
|
|
||||||
// CgoEnabled returns true if (and only if) CGo is enabled. It is true by
|
|
||||||
// default and false if CGO_ENABLED is set to "0".
|
|
||||||
func (c *Config) CgoEnabled() bool {
|
|
||||||
return goenv.Get("CGO_ENABLED") == "1"
|
|
||||||
}
|
|
||||||
|
|
||||||
// GC returns the garbage collection strategy in use on this platform. Valid
|
// GC returns the garbage collection strategy in use on this platform. Valid
|
||||||
// values are "none", "leaking", "conservative" and "precise".
|
// values are "none", "leaking", "conservative" and "precise".
|
||||||
func (c *Config) GC() string {
|
func (c *Config) GC() string {
|
||||||
@@ -189,6 +188,15 @@ func (c *Config) StackSize() uint64 {
|
|||||||
return c.Target.DefaultStackSize
|
return c.Target.DefaultStackSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MaxStackAlloc returns the size of the maximum allocation to put on the stack vs heap.
|
||||||
|
func (c *Config) MaxStackAlloc() uint64 {
|
||||||
|
if c.StackSize() > 32*1024 {
|
||||||
|
return 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
return 256
|
||||||
|
}
|
||||||
|
|
||||||
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
|
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
|
||||||
// calculates and patches in the checksum for the 2nd stage bootloader.
|
// calculates and patches in the checksum for the 2nd stage bootloader.
|
||||||
func (c *Config) RP2040BootPatch() bool {
|
func (c *Config) RP2040BootPatch() bool {
|
||||||
@@ -272,10 +280,6 @@ func (c *Config) CFlags(libclang bool) []string {
|
|||||||
cflags = append(cflags,
|
cflags = append(cflags,
|
||||||
"-resource-dir="+resourceDir,
|
"-resource-dir="+resourceDir,
|
||||||
)
|
)
|
||||||
if strings.HasPrefix(c.Triple(), "xtensa") {
|
|
||||||
// workaround needed in LLVM 16, see: https://github.com/espressif/llvm-project/issues/83
|
|
||||||
cflags = append(cflags, "-isystem", filepath.Join(resourceDir, "include"))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
switch c.Target.Libc {
|
switch c.Target.Libc {
|
||||||
case "darwin-libSystem":
|
case "darwin-libSystem":
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
|
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
|
||||||
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
|
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
|
||||||
validSerialOptions = []string{"none", "uart", "usb"}
|
validSerialOptions = []string{"none", "uart", "usb", "rtt"}
|
||||||
validPrintSizeOptions = []string{"none", "short", "full"}
|
validPrintSizeOptions = []string{"none", "short", "full"}
|
||||||
validPanicStrategyOptions = []string{"print", "trap"}
|
validPanicStrategyOptions = []string{"print", "trap"}
|
||||||
validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
|
validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
|
||||||
@@ -23,6 +23,7 @@ type Options struct {
|
|||||||
GOOS string // environment variable
|
GOOS string // environment variable
|
||||||
GOARCH string // environment variable
|
GOARCH string // environment variable
|
||||||
GOARM string // environment variable (only used with GOARCH=arm)
|
GOARM string // environment variable (only used with GOARCH=arm)
|
||||||
|
Directory string // working dir, leave it unset to use the current working dir
|
||||||
Target string
|
Target string
|
||||||
Opt string
|
Opt string
|
||||||
GC string
|
GC string
|
||||||
@@ -48,7 +49,6 @@ type Options struct {
|
|||||||
Programmer string
|
Programmer string
|
||||||
OpenOCDCommands []string
|
OpenOCDCommands []string
|
||||||
LLVMFeatures string
|
LLVMFeatures string
|
||||||
Directory string
|
|
||||||
PrintJSON bool
|
PrintJSON bool
|
||||||
Monitor bool
|
Monitor bool
|
||||||
BaudRate int
|
BaudRate int
|
||||||
|
|||||||
+19
-3
@@ -301,10 +301,10 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
switch goarch {
|
switch goarch {
|
||||||
case "386":
|
case "386":
|
||||||
spec.CPU = "pentium4"
|
spec.CPU = "pentium4"
|
||||||
spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
||||||
case "amd64":
|
case "amd64":
|
||||||
spec.CPU = "x86-64"
|
spec.CPU = "x86-64"
|
||||||
spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
spec.Features = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
||||||
case "arm":
|
case "arm":
|
||||||
spec.CPU = "generic"
|
spec.CPU = "generic"
|
||||||
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
|
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
|
||||||
@@ -320,8 +320,10 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
spec.CPU = "generic"
|
spec.CPU = "generic"
|
||||||
if goos == "darwin" {
|
if goos == "darwin" {
|
||||||
spec.Features = "+neon"
|
spec.Features = "+neon"
|
||||||
} else { // windows, linux
|
} else if goos == "windows" {
|
||||||
spec.Features = "+neon,-fmv"
|
spec.Features = "+neon,-fmv"
|
||||||
|
} else { // linux
|
||||||
|
spec.Features = "+neon,-fmv,-outline-atomics"
|
||||||
}
|
}
|
||||||
case "wasm":
|
case "wasm":
|
||||||
spec.CPU = "generic"
|
spec.CPU = "generic"
|
||||||
@@ -349,6 +351,20 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
spec.RTLib = "compiler-rt"
|
spec.RTLib = "compiler-rt"
|
||||||
spec.Libc = "musl"
|
spec.Libc = "musl"
|
||||||
spec.LDFlags = append(spec.LDFlags, "--gc-sections")
|
spec.LDFlags = append(spec.LDFlags, "--gc-sections")
|
||||||
|
if goarch == "arm64" {
|
||||||
|
// Disable outline atomics. For details, see:
|
||||||
|
// https://cpufun.substack.com/p/atomics-in-aarch64
|
||||||
|
// A better way would be to fully support outline atomics, which
|
||||||
|
// makes atomics slightly more efficient on systems with many cores.
|
||||||
|
// But the instructions are only supported on newer aarch64 CPUs, so
|
||||||
|
// this feature is normally put in a system library which does
|
||||||
|
// feature detection for you.
|
||||||
|
// We take the lazy way out and simply disable this feature, instead
|
||||||
|
// of enabling it in compiler-rt (which is a bit more complicated).
|
||||||
|
// We don't really need this feature anyway as we don't even support
|
||||||
|
// proper threading.
|
||||||
|
spec.CFlags = append(spec.CFlags, "-mno-outline-atomics")
|
||||||
|
}
|
||||||
} else if goos == "windows" {
|
} else if goos == "windows" {
|
||||||
spec.Linker = "ld.lld"
|
spec.Linker = "ld.lld"
|
||||||
spec.Libc = "mingw-w64"
|
spec.Libc = "mingw-w64"
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ type Config struct {
|
|||||||
Scheduler string
|
Scheduler string
|
||||||
AutomaticStackSize bool
|
AutomaticStackSize bool
|
||||||
DefaultStackSize uint64
|
DefaultStackSize uint64
|
||||||
|
MaxStackAlloc uint64
|
||||||
NeedsStackObjects bool
|
NeedsStackObjects bool
|
||||||
Debug bool // Whether to emit debug information in the LLVM module.
|
Debug bool // Whether to emit debug information in the LLVM module.
|
||||||
}
|
}
|
||||||
@@ -1997,8 +1998,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
case *ssa.Alloc:
|
case *ssa.Alloc:
|
||||||
typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
|
||||||
size := b.targetData.TypeAllocSize(typ)
|
size := b.targetData.TypeAllocSize(typ)
|
||||||
// Move all "large" allocations to the heap. This value is also transform.maxStackAlloc.
|
// Move all "large" allocations to the heap.
|
||||||
if expr.Heap || size > 256 {
|
if expr.Heap || size > b.MaxStackAlloc {
|
||||||
// Calculate ^uintptr(0)
|
// Calculate ^uintptr(0)
|
||||||
maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue()
|
maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue()
|
||||||
if size > maxSize {
|
if size > maxSize {
|
||||||
@@ -3261,7 +3262,11 @@ func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) {
|
|||||||
// Instead of a load from the global, create a bitcast of the
|
// Instead of a load from the global, create a bitcast of the
|
||||||
// function pointer itself.
|
// function pointer itself.
|
||||||
name := strings.TrimSuffix(unop.X.(*ssa.Global).Name(), "$funcaddr")
|
name := strings.TrimSuffix(unop.X.(*ssa.Global).Name(), "$funcaddr")
|
||||||
_, fn := b.getFunction(b.fn.Pkg.Members[name].(*ssa.Function))
|
pkg := b.fn.Pkg
|
||||||
|
if pkg == nil {
|
||||||
|
pkg = b.fn.Origin().Pkg
|
||||||
|
}
|
||||||
|
_, fn := b.getFunction(pkg.Members[name].(*ssa.Function))
|
||||||
if fn.IsNil() {
|
if fn.IsNil() {
|
||||||
return llvm.Value{}, b.makeError(unop.Pos(), "cgo function not found: "+name)
|
return llvm.Value{}, b.makeError(unop.Pos(), "cgo function not found: "+name)
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-12
@@ -684,19 +684,25 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
|||||||
|
|
||||||
actualTypeNum := b.CreateExtractValue(itf, 0, "interface.type")
|
actualTypeNum := b.CreateExtractValue(itf, 0, "interface.type")
|
||||||
commaOk := llvm.Value{}
|
commaOk := llvm.Value{}
|
||||||
if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
|
|
||||||
// Type assert on interface type.
|
|
||||||
// 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}, "")
|
|
||||||
|
|
||||||
|
if intf, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
|
||||||
|
if intf.Empty() {
|
||||||
|
// intf is the empty interface => no methods
|
||||||
|
// 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}, "")
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
name, _ := getTypeCodeName(expr.AssertedType)
|
name, _ := getTypeCodeName(expr.AssertedType)
|
||||||
globalName := "reflect/types.typeid:" + name
|
globalName := "reflect/types.typeid:" + name
|
||||||
|
|||||||
Generated
+4
-4
@@ -20,16 +20,16 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1696983906,
|
"lastModified": 1703068421,
|
||||||
"narHash": "sha256-L7GyeErguS7Pg4h8nK0wGlcUTbfUMDu+HMf1UcyP72k=",
|
"narHash": "sha256-WSw5Faqlw75McIflnl5v7qVD/B3S2sLh+968bpOGrWA=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "bd1cde45c77891214131cbbea5b1203e485a9d51",
|
"rev": "d65bceaee0fb1e64363f7871bc43dc1c6ecad99f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"id": "nixpkgs",
|
"id": "nixpkgs",
|
||||||
"ref": "nixos-23.05",
|
"ref": "nixos-23.11",
|
||||||
"type": "indirect"
|
"type": "indirect"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
inputs = {
|
inputs = {
|
||||||
# Use a recent stable release, but fix the version to make it reproducible.
|
# Use a recent stable release, but fix the version to make it reproducible.
|
||||||
# This version should be updated from time to time.
|
# This version should be updated from time to time.
|
||||||
nixpkgs.url = "nixpkgs/nixos-23.05";
|
nixpkgs.url = "nixpkgs/nixos-23.11";
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
};
|
};
|
||||||
outputs = { self, nixpkgs, flake-utils }:
|
outputs = { self, nixpkgs, flake-utils }:
|
||||||
@@ -49,11 +49,12 @@
|
|||||||
buildInputs = [
|
buildInputs = [
|
||||||
# These dependencies are required for building tinygo (go install).
|
# These dependencies are required for building tinygo (go install).
|
||||||
go
|
go
|
||||||
llvmPackages_16.llvm
|
llvmPackages_17.llvm
|
||||||
llvmPackages_16.libclang
|
llvmPackages_17.libclang
|
||||||
|
llvmPackages_17.libcxx
|
||||||
# Additional dependencies needed at runtime, for building and/or
|
# Additional dependencies needed at runtime, for building and/or
|
||||||
# flashing.
|
# flashing.
|
||||||
llvmPackages_16.lld
|
llvmPackages_17.lld
|
||||||
avrdude
|
avrdude
|
||||||
binaryen
|
binaryen
|
||||||
# Additional dependencies needed for on-chip debugging.
|
# Additional dependencies needed for on-chip debugging.
|
||||||
@@ -68,7 +69,7 @@
|
|||||||
# Without setting these explicitly, Homebrew versions might be used
|
# Without setting these explicitly, Homebrew versions might be used
|
||||||
# or the default `ar` and `nm` tools might be used (which don't
|
# or the default `ar` and `nm` tools might be used (which don't
|
||||||
# support wasi).
|
# support wasi).
|
||||||
export CLANG="clang-16 -resource-dir ${llvmPackages_16.clang.cc.lib}/lib/clang/16"
|
export CLANG="clang-17 -resource-dir ${llvmPackages_17.clang.cc.lib}/lib/clang/17"
|
||||||
export LLVM_AR=llvm-ar
|
export LLVM_AR=llvm-ar
|
||||||
export LLVM_NM=llvm-nm
|
export LLVM_NM=llvm-nm
|
||||||
|
|
||||||
@@ -77,7 +78,7 @@
|
|||||||
export MD5SUM=md5sum
|
export MD5SUM=md5sum
|
||||||
|
|
||||||
# Ugly hack to make the Clang resources directory available.
|
# Ugly hack to make the Clang resources directory available.
|
||||||
export GOFLAGS="\"-ldflags=-X github.com/tinygo-org/tinygo/goenv.clangResourceDir=${llvmPackages_16.clang.cc.lib}/lib/clang/16"\"
|
export GOFLAGS="\"-ldflags=-X github.com/tinygo-org/tinygo/goenv.clangResourceDir=${llvmPackages_17.clang.cc.lib}/lib/clang/17"\"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,11 @@ require (
|
|||||||
github.com/mattn/go-tty v0.0.4
|
github.com/mattn/go-tty v0.0.4
|
||||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
||||||
go.bug.st/serial v1.6.0
|
go.bug.st/serial v1.6.0
|
||||||
golang.org/x/sys v0.11.0
|
golang.org/x/net v0.20.0
|
||||||
golang.org/x/tools v0.12.0
|
golang.org/x/sys v0.16.0
|
||||||
|
golang.org/x/tools v0.17.0
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
tinygo.org/x/go-llvm v0.0.0-20231014233752-75a8a9fe6f74
|
tinygo.org/x/go-llvm v0.0.0-20240106122909-c2c543540318
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -30,4 +31,5 @@ require (
|
|||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||||
|
golang.org/x/text v0.14.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -48,7 +48,9 @@ github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9
|
|||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
|
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
|
||||||
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
||||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||||
|
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
|
||||||
|
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
|
||||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -56,14 +58,16 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||||
|
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/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 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||||
tinygo.org/x/go-llvm v0.0.0-20231014233752-75a8a9fe6f74 h1:tW8XhLI9gUZLL+2pG0HYb5dc6bpMj1aqtESpizXPnMY=
|
tinygo.org/x/go-llvm v0.0.0-20240106122909-c2c543540318 h1:4KjZvPtcN1UwobevcGbdzeinx0L1i8HDdJu84bu7NI8=
|
||||||
tinygo.org/x/go-llvm v0.0.0-20231014233752-75a8a9fe6f74/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
tinygo.org/x/go-llvm v0.0.0-20240106122909-c2c543540318/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||||
|
|||||||
+2
-5
@@ -142,11 +142,8 @@ func Get(name string) string {
|
|||||||
}
|
}
|
||||||
return filepath.Join(dir, "tinygo")
|
return filepath.Join(dir, "tinygo")
|
||||||
case "CGO_ENABLED":
|
case "CGO_ENABLED":
|
||||||
val := os.Getenv("CGO_ENABLED")
|
// Always enable CGo. It is required by a number of targets, including
|
||||||
if val == "1" || val == "0" {
|
// macOS and the rp2040.
|
||||||
return val
|
|
||||||
}
|
|
||||||
// Default to enabling CGo.
|
|
||||||
return "1"
|
return "1"
|
||||||
case "TINYGOROOT":
|
case "TINYGOROOT":
|
||||||
return sourceDir()
|
return sourceDir()
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ import (
|
|||||||
|
|
||||||
// Version of TinyGo.
|
// Version of TinyGo.
|
||||||
// Update this value before release of new version of software.
|
// Update this value before release of new version of software.
|
||||||
const version = "0.31.0-dev"
|
const version = "0.31.2"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// This variable is set at build time using -ldflags parameters.
|
// This variable is set at build time using -ldflags parameters.
|
||||||
|
|||||||
+27
-10
@@ -239,7 +239,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
// already be emitted in initAll.
|
// already be emitted in initAll.
|
||||||
continue
|
continue
|
||||||
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" || callFn.name == "runtime.hashmapInterfaceHash" ||
|
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" || callFn.name == "runtime.hashmapInterfaceHash" ||
|
||||||
callFn.name == "os.runtime_args" || callFn.name == "internal/task.start" || callFn.name == "internal/task.Current":
|
callFn.name == "os.runtime_args" || callFn.name == "internal/task.start" || callFn.name == "internal/task.Current" ||
|
||||||
|
callFn.name == "time.startTimer" || callFn.name == "time.stopTimer" || callFn.name == "time.resetTimer":
|
||||||
// These functions should be run at runtime. Specifically:
|
// These functions should be run at runtime. Specifically:
|
||||||
// * Print and panic functions are best emitted directly without
|
// * Print and panic functions are best emitted directly without
|
||||||
// interpreting them, otherwise we get a ton of putchar (etc.)
|
// interpreting them, otherwise we get a ton of putchar (etc.)
|
||||||
@@ -252,6 +253,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
// at runtime.
|
// at runtime.
|
||||||
// * internal/task.start, internal/task.Current: start and read shcheduler state,
|
// * internal/task.start, internal/task.Current: start and read shcheduler state,
|
||||||
// which is modified elsewhere.
|
// which is modified elsewhere.
|
||||||
|
// * Timer functions access runtime internal state which may
|
||||||
|
// not be initialized.
|
||||||
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, err
|
return nil, mem, err
|
||||||
@@ -424,7 +427,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
methodSetPtr, err := mem.load(typecodePtr.addOffset(-int64(r.pointerSize)), r.pointerSize).asPointer(r)
|
typecodePtrOffset, err := typecodePtr.addOffset(-int64(r.pointerSize))
|
||||||
|
if err != nil {
|
||||||
|
return nil, mem, r.errorAt(inst, err) // unlikely
|
||||||
|
}
|
||||||
|
methodSetPtr, err := mem.load(typecodePtrOffset, r.pointerSize).asPointer(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
@@ -470,7 +477,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
methodSetPtr, err := mem.load(typecodePtr.addOffset(-int64(r.pointerSize)), r.pointerSize).asPointer(r)
|
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 {
|
if err != nil {
|
||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
@@ -633,11 +644,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
case llvm.GetElementPtr:
|
case llvm.GetElementPtr:
|
||||||
// GetElementPtr does pointer arithmetic, changing the offset of the
|
// GetElementPtr does pointer arithmetic, changing the offset of the
|
||||||
// pointer into the underlying object.
|
// pointer into the underlying object.
|
||||||
var offset uint64
|
var offset int64
|
||||||
for i := 1; i < len(operands); i += 2 {
|
for i := 1; i < len(operands); i += 2 {
|
||||||
index := operands[i].Uint()
|
index := operands[i].Int()
|
||||||
elementSize := operands[i+1].Uint()
|
elementSize := operands[i+1].Int()
|
||||||
if int64(elementSize) < 0 {
|
if elementSize < 0 {
|
||||||
// This is a struct field.
|
// This is a struct field.
|
||||||
offset += index
|
offset += index
|
||||||
} else {
|
} else {
|
||||||
@@ -651,11 +662,14 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
return nil, mem, r.errorAt(inst, err)
|
return nil, mem, r.errorAt(inst, err)
|
||||||
}
|
}
|
||||||
// GEP on fixed pointer value (for example, memory-mapped I/O).
|
// GEP on fixed pointer value (for example, memory-mapped I/O).
|
||||||
ptrValue := operands[0].Uint() + offset
|
ptrValue := operands[0].Uint() + uint64(offset)
|
||||||
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
|
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ptr = ptr.addOffset(int64(offset))
|
ptr, err = ptr.addOffset(int64(offset))
|
||||||
|
if err != nil {
|
||||||
|
return nil, mem, r.errorAt(inst, err)
|
||||||
|
}
|
||||||
locals[inst.localIndex] = ptr
|
locals[inst.localIndex] = ptr
|
||||||
if r.debug {
|
if r.debug {
|
||||||
fmt.Fprintln(os.Stderr, indent+"gep:", operands, "->", ptr)
|
fmt.Fprintln(os.Stderr, indent+"gep:", operands, "->", ptr)
|
||||||
@@ -753,7 +767,10 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
|||||||
if inst.opcode == llvm.Add {
|
if inst.opcode == llvm.Add {
|
||||||
// This likely means this is part of a
|
// This likely means this is part of a
|
||||||
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
|
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
|
||||||
lhsPtr = lhsPtr.addOffset(int64(rhs.Uint()))
|
lhsPtr, err = lhsPtr.addOffset(int64(rhs.Uint()))
|
||||||
|
if err != nil {
|
||||||
|
return nil, mem, r.errorAt(inst, err)
|
||||||
|
}
|
||||||
locals[inst.localIndex] = lhsPtr
|
locals[inst.localIndex] = lhsPtr
|
||||||
} else if inst.opcode == llvm.Xor && rhs.Uint() == 0 {
|
} else if inst.opcode == llvm.Xor && rhs.Uint() == 0 {
|
||||||
// Special workaround for strings.noescape, see
|
// Special workaround for strings.noescape, see
|
||||||
|
|||||||
+3
-3
@@ -517,12 +517,12 @@ func (v pointerValue) offset() uint32 {
|
|||||||
// addOffset essentially does a GEP operation (pointer arithmetic): it adds the
|
// addOffset essentially does a GEP operation (pointer arithmetic): it adds the
|
||||||
// offset to the pointer. It also checks that the offset doesn't overflow the
|
// offset to the pointer. It also checks that the offset doesn't overflow the
|
||||||
// maximum offset size (which is 4GB).
|
// maximum offset size (which is 4GB).
|
||||||
func (v pointerValue) addOffset(offset int64) pointerValue {
|
func (v pointerValue) addOffset(offset int64) (pointerValue, error) {
|
||||||
result := pointerValue{v.pointer + uint64(offset)}
|
result := pointerValue{v.pointer + uint64(offset)}
|
||||||
if checks && v.index() != result.index() {
|
if checks && v.index() != result.index() {
|
||||||
panic("interp: offset out of range")
|
return result, fmt.Errorf("interp: offset %d out of range for object %v", offset, v)
|
||||||
}
|
}
|
||||||
return result
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v pointerValue) len(r *runner) uint32 {
|
func (v pointerValue) len(r *runner) uint32 {
|
||||||
|
|||||||
Vendored
+7
@@ -10,6 +10,8 @@ target triple = "x86_64--linux"
|
|||||||
@main.exposedValue1 = global i16 0
|
@main.exposedValue1 = global i16 0
|
||||||
@main.exposedValue2 = global i16 0
|
@main.exposedValue2 = global i16 0
|
||||||
@main.insertedValue = global {i8, i32, {float, {i64, i16}}} zeroinitializer
|
@main.insertedValue = global {i8, i32, {float, {i64, i16}}} zeroinitializer
|
||||||
|
@main.gepArray = global [8 x i8] zeroinitializer
|
||||||
|
@main.negativeGEP = global ptr null
|
||||||
|
|
||||||
declare void @runtime.printint64(i64) unnamed_addr
|
declare void @runtime.printint64(i64) unnamed_addr
|
||||||
|
|
||||||
@@ -88,6 +90,11 @@ entry:
|
|||||||
%agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
|
%agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
|
||||||
store {i8, i32, {float, {i64, i16}}} %agg2, ptr @main.insertedValue
|
store {i8, i32, {float, {i64, i16}}} %agg2, ptr @main.insertedValue
|
||||||
|
|
||||||
|
; negative GEP instruction
|
||||||
|
%ngep1 = getelementptr [8 x i8], ptr @main.negativeGEP, i32 0, i32 5
|
||||||
|
%ngep2 = getelementptr [8 x i8], ptr %ngep1, i32 0, i32 -3
|
||||||
|
store ptr %ngep2, ptr @main.negativeGEP
|
||||||
|
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
@@ -9,6 +9,8 @@ target triple = "x86_64--linux"
|
|||||||
@main.exposedValue1 = global i16 0
|
@main.exposedValue1 = global i16 0
|
||||||
@main.exposedValue2 = local_unnamed_addr global i16 0
|
@main.exposedValue2 = local_unnamed_addr global i16 0
|
||||||
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
|
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
|
||||||
|
@main.gepArray = local_unnamed_addr global [8 x i8] zeroinitializer
|
||||||
|
@main.negativeGEP = global ptr getelementptr inbounds (i8, ptr @main.negativeGEP, i64 2)
|
||||||
|
|
||||||
declare void @runtime.printint64(i64) unnamed_addr
|
declare void @runtime.printint64(i64) unnamed_addr
|
||||||
|
|
||||||
|
|||||||
+1
-1
Submodule lib/cmsis-svd updated: df75ff974c...40327a4d2d
+1
-1
Submodule lib/wasi-libc updated: 30094b6ed0...1dfe5c302d
@@ -232,6 +232,7 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
|
|||||||
"": true,
|
"": true,
|
||||||
"crypto/": true,
|
"crypto/": true,
|
||||||
"crypto/rand/": false,
|
"crypto/rand/": false,
|
||||||
|
"crypto/tls/": false,
|
||||||
"device/": false,
|
"device/": false,
|
||||||
"examples/": false,
|
"examples/": false,
|
||||||
"internal/": true,
|
"internal/": true,
|
||||||
@@ -241,7 +242,9 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
|
|||||||
"internal/task/": false,
|
"internal/task/": false,
|
||||||
"machine/": false,
|
"machine/": false,
|
||||||
"net/": true,
|
"net/": true,
|
||||||
|
"net/http/": false,
|
||||||
"os/": true,
|
"os/": true,
|
||||||
|
"os/user/": false,
|
||||||
"reflect/": false,
|
"reflect/": false,
|
||||||
"runtime/": false,
|
"runtime/": false,
|
||||||
"sync/": true,
|
"sync/": true,
|
||||||
|
|||||||
+1
-5
@@ -22,12 +22,8 @@ func List(config *compileopts.Config, extraArgs, pkgs []string) (*exec.Cmd, erro
|
|||||||
args = append(args, "-tags", strings.Join(config.BuildTags(), " "))
|
args = append(args, "-tags", strings.Join(config.BuildTags(), " "))
|
||||||
}
|
}
|
||||||
args = append(args, pkgs...)
|
args = append(args, pkgs...)
|
||||||
cgoEnabled := "0"
|
|
||||||
if config.CgoEnabled() {
|
|
||||||
cgoEnabled = "1"
|
|
||||||
}
|
|
||||||
cmd := exec.Command(filepath.Join(goenv.Get("GOROOT"), "bin", "go"), args...)
|
cmd := exec.Command(filepath.Join(goenv.Get("GOROOT"), "bin", "go"), args...)
|
||||||
cmd.Env = append(os.Environ(), "GOROOT="+goroot, "GOOS="+config.GOOS(), "GOARCH="+config.GOARCH(), "CGO_ENABLED="+cgoEnabled)
|
cmd.Env = append(os.Environ(), "GOROOT="+goroot, "GOOS="+config.GOOS(), "GOARCH="+config.GOARCH(), "CGO_ENABLED=1")
|
||||||
if config.Options.Directory != "" {
|
if config.Options.Directory != "" {
|
||||||
cmd.Dir = config.Options.Directory
|
cmd.Dir = config.Options.Directory
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-1
@@ -27,6 +27,8 @@ import (
|
|||||||
"github.com/tinygo-org/tinygo/goenv"
|
"github.com/tinygo-org/tinygo/goenv"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var initFileVersions = func(info *types.Info) {}
|
||||||
|
|
||||||
// Program holds all packages and some metadata about the program as a whole.
|
// Program holds all packages and some metadata about the program as a whole.
|
||||||
type Program struct {
|
type Program struct {
|
||||||
config *compileopts.Config
|
config *compileopts.Config
|
||||||
@@ -378,6 +380,24 @@ func (p *Package) Check() error {
|
|||||||
typeErrors = append(typeErrors, err)
|
typeErrors = append(typeErrors, err)
|
||||||
}
|
}
|
||||||
checker.Importer = p
|
checker.Importer = p
|
||||||
|
if p.Module.GoVersion != "" {
|
||||||
|
// Setting the Go version for a module makes sure the type checker
|
||||||
|
// errors out on language features not supported in that particular
|
||||||
|
// version.
|
||||||
|
checker.GoVersion = "go" + p.Module.GoVersion
|
||||||
|
} else {
|
||||||
|
// Version is not known, so use the currently installed Go version.
|
||||||
|
// This is needed for `tinygo run` for example.
|
||||||
|
// Normally we'd use goenv.GorootVersionString(), but for compatibility
|
||||||
|
// with Go 1.20 and below we need a version in the form of "go1.12" (no
|
||||||
|
// patch version).
|
||||||
|
major, minor, err := goenv.GetGorootVersion()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
checker.GoVersion = fmt.Sprintf("go%d.%d", major, minor)
|
||||||
|
}
|
||||||
|
initFileVersions(&p.info)
|
||||||
|
|
||||||
// Do typechecking of the package.
|
// Do typechecking of the package.
|
||||||
packageName := p.ImportPath
|
packageName := p.ImportPath
|
||||||
@@ -447,7 +467,7 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
|||||||
if errs != nil {
|
if errs != nil {
|
||||||
fileErrs = append(fileErrs, errs...)
|
fileErrs = append(fileErrs, errs...)
|
||||||
}
|
}
|
||||||
files = append(files, generated)
|
files = append(files, generated...)
|
||||||
p.program.LDFlags = append(p.program.LDFlags, ldflags...)
|
p.program.LDFlags = append(p.program.LDFlags, ldflags...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
//go:build go1.22
|
||||||
|
|
||||||
|
// types.Info.FileVersions was added in Go 1.22, so we can only initialize it
|
||||||
|
// when built with Go 1.22.
|
||||||
|
|
||||||
|
package loader
|
||||||
|
|
||||||
|
import (
|
||||||
|
"go/ast"
|
||||||
|
"go/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initFileVersions = func(info *types.Info) {
|
||||||
|
info.FileVersions = make(map[*ast.File]string)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -532,7 +532,7 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
|||||||
return fmt.Errorf("unknown flash method: %s", flashMethod)
|
return fmt.Errorf("unknown flash method: %s", flashMethod)
|
||||||
}
|
}
|
||||||
if options.Monitor {
|
if options.Monitor {
|
||||||
return Monitor(result.Executable, "", options)
|
return Monitor(result.Executable, "", config)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -1225,6 +1225,7 @@ func usage(command string) {
|
|||||||
fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB")
|
fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB")
|
||||||
fmt.Fprintln(os.Stderr, " lldb: run/flash and immediately enter LLDB")
|
fmt.Fprintln(os.Stderr, " lldb: run/flash and immediately enter LLDB")
|
||||||
fmt.Fprintln(os.Stderr, " monitor: open communication port")
|
fmt.Fprintln(os.Stderr, " monitor: open communication port")
|
||||||
|
fmt.Fprintln(os.Stderr, " ports: list available serial ports")
|
||||||
fmt.Fprintln(os.Stderr, " env: list environment variables used during build")
|
fmt.Fprintln(os.Stderr, " env: list environment variables used during build")
|
||||||
fmt.Fprintln(os.Stderr, " list: run go list using the TinyGo root")
|
fmt.Fprintln(os.Stderr, " list: run go list using the TinyGo root")
|
||||||
fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+goenv.Get("GOCACHE")+")")
|
fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+goenv.Get("GOCACHE")+")")
|
||||||
@@ -1437,7 +1438,6 @@ func main() {
|
|||||||
llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable")
|
llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable")
|
||||||
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
|
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
|
||||||
monitor := flag.Bool("monitor", false, "enable serial monitor")
|
monitor := flag.Bool("monitor", false, "enable serial monitor")
|
||||||
info := flag.Bool("info", false, "print information")
|
|
||||||
baudrate := flag.Int("baudrate", 115200, "baudrate of serial monitor")
|
baudrate := flag.Int("baudrate", 115200, "baudrate of serial monitor")
|
||||||
|
|
||||||
// Internal flags, that are only intended for TinyGo development.
|
// Internal flags, that are only intended for TinyGo development.
|
||||||
@@ -1733,15 +1733,19 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
case "monitor":
|
case "monitor":
|
||||||
if *info {
|
config, err := builder.NewConfig(options)
|
||||||
serialPortInfo, err := ListSerialPorts()
|
handleCompilerError(err)
|
||||||
handleCompilerError(err)
|
err = Monitor("", *port, config)
|
||||||
for _, s := range serialPortInfo {
|
handleCompilerError(err)
|
||||||
fmt.Printf("%s %4s %4s %s\n", s.Name, s.VID, s.PID, s.Target)
|
case "ports":
|
||||||
}
|
serialPortInfo, err := ListSerialPorts()
|
||||||
} else {
|
handleCompilerError(err)
|
||||||
err := Monitor("", *port, options)
|
if len(serialPortInfo) == 0 {
|
||||||
handleCompilerError(err)
|
fmt.Println("No serial ports found.")
|
||||||
|
}
|
||||||
|
fmt.Printf("%-20s %-9s %s\n", "Port", "ID", "Boards")
|
||||||
|
for _, s := range serialPortInfo {
|
||||||
|
fmt.Printf("%-20s %4s:%4s %s\n", s.Name, s.VID, s.PID, s.Target)
|
||||||
}
|
}
|
||||||
case "targets":
|
case "targets":
|
||||||
specs, err := compileopts.GetTargetSpecs()
|
specs, err := compileopts.GetTargetSpecs()
|
||||||
|
|||||||
+8
-1
@@ -69,6 +69,7 @@ func TestBuild(t *testing.T) {
|
|||||||
"json.go",
|
"json.go",
|
||||||
"map.go",
|
"map.go",
|
||||||
"math.go",
|
"math.go",
|
||||||
|
"oldgo/",
|
||||||
"print.go",
|
"print.go",
|
||||||
"reflect.go",
|
"reflect.go",
|
||||||
"slice.go",
|
"slice.go",
|
||||||
@@ -90,6 +91,9 @@ func TestBuild(t *testing.T) {
|
|||||||
if minor >= 21 {
|
if minor >= 21 {
|
||||||
tests = append(tests, "go1.21.go")
|
tests = append(tests, "go1.21.go")
|
||||||
}
|
}
|
||||||
|
if minor >= 22 {
|
||||||
|
tests = append(tests, "go1.22/")
|
||||||
|
}
|
||||||
|
|
||||||
if *testTarget != "" {
|
if *testTarget != "" {
|
||||||
// This makes it possible to run one specific test (instead of all),
|
// This makes it possible to run one specific test (instead of all),
|
||||||
@@ -333,8 +337,11 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
|||||||
path := TESTDATA + "/" + name
|
path := TESTDATA + "/" + name
|
||||||
// Get the expected output for this test.
|
// Get the expected output for this test.
|
||||||
txtpath := path[:len(path)-3] + ".txt"
|
txtpath := path[:len(path)-3] + ".txt"
|
||||||
|
pkgName := "./" + path
|
||||||
if path[len(path)-1] == '/' {
|
if path[len(path)-1] == '/' {
|
||||||
txtpath = path + "out.txt"
|
txtpath = path + "out.txt"
|
||||||
|
options.Directory = path
|
||||||
|
pkgName = "."
|
||||||
}
|
}
|
||||||
expected, err := os.ReadFile(txtpath)
|
expected, err := os.ReadFile(txtpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -348,7 +355,7 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
|||||||
|
|
||||||
// Build the test binary.
|
// Build the test binary.
|
||||||
stdout := &bytes.Buffer{}
|
stdout := &bytes.Buffer{}
|
||||||
_, err = buildAndRun("./"+path, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
_, err = buildAndRun(pkgName, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||||
return cmd.Run()
|
return cmd.Run()
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+143
-32
@@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"debug/dwarf"
|
"debug/dwarf"
|
||||||
"debug/elf"
|
"debug/elf"
|
||||||
"debug/macho"
|
"debug/macho"
|
||||||
@@ -9,6 +10,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"go/token"
|
"go/token"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"regexp"
|
"regexp"
|
||||||
@@ -17,7 +19,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/mattn/go-tty"
|
"github.com/mattn/go-tty"
|
||||||
"github.com/tinygo-org/tinygo/builder"
|
|
||||||
"github.com/tinygo-org/tinygo/compileopts"
|
"github.com/tinygo-org/tinygo/compileopts"
|
||||||
|
|
||||||
"go.bug.st/serial"
|
"go.bug.st/serial"
|
||||||
@@ -25,44 +26,151 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Monitor connects to the given port and reads/writes the serial port.
|
// Monitor connects to the given port and reads/writes the serial port.
|
||||||
func Monitor(executable, port string, options *compileopts.Options) error {
|
func Monitor(executable, port string, config *compileopts.Config) error {
|
||||||
config, err := builder.NewConfig(options)
|
const timeout = time.Second * 3
|
||||||
if err != nil {
|
var exit func() // function to be called before exiting
|
||||||
return err
|
var serialConn io.ReadWriter
|
||||||
}
|
|
||||||
|
|
||||||
wait := 300
|
if config.Options.Serial == "rtt" {
|
||||||
for i := 0; i <= wait; i++ {
|
// Use the RTT interface, which is documented (in part) here:
|
||||||
port, err = getDefaultPort(port, config.Target.SerialPort)
|
// https://wiki.segger.com/RTT
|
||||||
|
|
||||||
|
// Try to find the "machine.rttSerialInstance" symbol, which is the RTT
|
||||||
|
// control block.
|
||||||
|
file, err := elf.Open(executable)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if i < wait {
|
return fmt.Errorf("could not open ELF file to determine RTT control block: %w", err)
|
||||||
time.Sleep(10 * time.Millisecond)
|
}
|
||||||
continue
|
defer file.Close()
|
||||||
|
symbols, err := file.Symbols()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not read ELF symbol table to determine RTT control block: %w", err)
|
||||||
|
}
|
||||||
|
var address uint64
|
||||||
|
for _, symbol := range symbols {
|
||||||
|
if symbol.Name == "machine.rttSerialInstance" {
|
||||||
|
address = symbol.Value
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if address == 0 {
|
||||||
|
return fmt.Errorf("could not find RTT control block in ELF file")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start an openocd process in the background.
|
||||||
|
args, err := config.OpenOCDConfiguration()
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
break
|
args = append(args,
|
||||||
}
|
"-c", fmt.Sprintf("rtt setup 0x%x 16 \"SEGGER RTT\"", address),
|
||||||
|
"-c", "init",
|
||||||
br := options.BaudRate
|
"-c", "rtt server start 0 0")
|
||||||
if br <= 0 {
|
cmd := executeCommand(config.Options, "openocd", args...)
|
||||||
br = 115200
|
stderr, err := cmd.StderrPipe()
|
||||||
}
|
|
||||||
|
|
||||||
wait = 300
|
|
||||||
var p serial.Port
|
|
||||||
for i := 0; i <= wait; i++ {
|
|
||||||
p, err = serial.Open(port, &serial.Mode{BaudRate: br})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if i < wait {
|
|
||||||
time.Sleep(10 * time.Millisecond)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
break
|
cmd.Stdout = os.Stdout
|
||||||
|
err = cmd.Start()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer cmd.Process.Kill()
|
||||||
|
exit = func() {
|
||||||
|
// Make sure the openocd process is terminated at exit.
|
||||||
|
// This does not happen through the defer above when exiting through
|
||||||
|
// os.Exit.
|
||||||
|
cmd.Process.Kill()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the stderr, which logs various important messages we need.
|
||||||
|
r := bufio.NewReader(stderr)
|
||||||
|
var telnet net.Conn
|
||||||
|
var timeoutAt time.Time
|
||||||
|
for {
|
||||||
|
// Read the next line from the openocd process.
|
||||||
|
lineBytes, err := r.ReadBytes('\n')
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
line := string(lineBytes)
|
||||||
|
|
||||||
|
if line == "Info : rtt: No control block found\n" {
|
||||||
|
// Message that is sent back when OpenOCD can't find the control
|
||||||
|
// block after a 'rtt start' message.
|
||||||
|
if time.Now().After(timeoutAt) {
|
||||||
|
return fmt.Errorf("RTT timeout (could not locate RTT control block at 0x%08x)", address)
|
||||||
|
}
|
||||||
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
telnet.Write([]byte("rtt start\r\n"))
|
||||||
|
} else if strings.HasPrefix(line, "Info : Listening on port") {
|
||||||
|
// We need two different ports for controlling OpenOCD
|
||||||
|
// (typically port 4444) and the RTT channel 0 socket (arbitrary
|
||||||
|
// port).
|
||||||
|
var port int
|
||||||
|
var protocol string
|
||||||
|
fmt.Sscanf(line, "Info : Listening on port %d for %s connections\n", &port, &protocol)
|
||||||
|
if protocol == "telnet" && telnet == nil {
|
||||||
|
// Connect to the "telnet" command line interface.
|
||||||
|
telnet, err = net.Dial("tcp4", fmt.Sprintf("localhost:%d", port))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Tell OpenOCD to start scanning for the RTT control block.
|
||||||
|
telnet.Write([]byte("rtt start\r\n"))
|
||||||
|
// Also make sure we will time out if the control block just
|
||||||
|
// can't be found.
|
||||||
|
timeoutAt = time.Now().Add(timeout)
|
||||||
|
} else if protocol == "rtt" {
|
||||||
|
// Connect to the RTT channel, for both stdin and stdout.
|
||||||
|
conn, err := net.Dial("tcp4", fmt.Sprintf("localhost:%d", port))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
serialConn = conn
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(line, "Info : rtt: Control block found at") {
|
||||||
|
// Connection established!
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // -serial=uart or -serial=usb
|
||||||
|
var err error
|
||||||
|
wait := 300
|
||||||
|
for i := 0; i <= wait; i++ {
|
||||||
|
port, err = getDefaultPort(port, config.Target.SerialPort)
|
||||||
|
if err != nil {
|
||||||
|
if i < wait {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
br := config.Options.BaudRate
|
||||||
|
if br <= 0 {
|
||||||
|
br = 115200
|
||||||
|
}
|
||||||
|
|
||||||
|
wait = 300
|
||||||
|
var p serial.Port
|
||||||
|
for i := 0; i <= wait; i++ {
|
||||||
|
p, err = serial.Open(port, &serial.Mode{BaudRate: br})
|
||||||
|
if err != nil {
|
||||||
|
if i < wait {
|
||||||
|
time.Sleep(10 * time.Millisecond)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
serialConn = p
|
||||||
|
break
|
||||||
|
}
|
||||||
|
defer p.Close()
|
||||||
}
|
}
|
||||||
defer p.Close()
|
|
||||||
|
|
||||||
tty, err := tty.Open()
|
tty, err := tty.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -77,6 +185,9 @@ func Monitor(executable, port string, options *compileopts.Options) error {
|
|||||||
go func() {
|
go func() {
|
||||||
<-sig
|
<-sig
|
||||||
tty.Close()
|
tty.Close()
|
||||||
|
if exit != nil {
|
||||||
|
exit()
|
||||||
|
}
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
@@ -88,7 +199,7 @@ func Monitor(executable, port string, options *compileopts.Options) error {
|
|||||||
buf := make([]byte, 100*1024)
|
buf := make([]byte, 100*1024)
|
||||||
var line []byte
|
var line []byte
|
||||||
for {
|
for {
|
||||||
n, err := p.Read(buf)
|
n, err := serialConn.Read(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errCh <- fmt.Errorf("read error: %w", err)
|
errCh <- fmt.Errorf("read error: %w", err)
|
||||||
return
|
return
|
||||||
@@ -124,7 +235,7 @@ func Monitor(executable, port string, options *compileopts.Options) error {
|
|||||||
if r == 0 {
|
if r == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p.Write([]byte(string(r)))
|
serialConn.Write([]byte(string(r)))
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
//go:build nrf || stm32 || (sam && atsamd51) || (sam && atsame5x)
|
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3
|
||||||
|
|
||||||
|
// If you update the above build constraint, you'll probably also need to update
|
||||||
|
// src/runtime/rand_hwrng.go.
|
||||||
|
|
||||||
package rand
|
package rand
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,447 @@
|
|||||||
|
// TINYGO: The following is copied and modified from Go 1.19.3 official implementation.
|
||||||
|
|
||||||
|
// Copyright 2009 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 tls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto"
|
||||||
|
"crypto/x509"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CurveID is the type of a TLS identifier for an elliptic curve. See
|
||||||
|
// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8.
|
||||||
|
//
|
||||||
|
// In TLS 1.3, this type is called NamedGroup, but at this time this library
|
||||||
|
// only supports Elliptic Curve based groups. See RFC 8446, Section 4.2.7.
|
||||||
|
type CurveID uint16
|
||||||
|
|
||||||
|
// ConnectionState records basic TLS details about the connection.
|
||||||
|
type ConnectionState struct {
|
||||||
|
// TINYGO: empty; TLS connection offloaded to device
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientAuthType declares the policy the server will follow for
|
||||||
|
// TLS Client Authentication.
|
||||||
|
type ClientAuthType int
|
||||||
|
|
||||||
|
// ClientSessionCache is a cache of ClientSessionState objects that can be used
|
||||||
|
// by a client to resume a TLS session with a given server. ClientSessionCache
|
||||||
|
// implementations should expect to be called concurrently from different
|
||||||
|
// goroutines. Up to TLS 1.2, only ticket-based resumption is supported, not
|
||||||
|
// SessionID-based resumption. In TLS 1.3 they were merged into PSK modes, which
|
||||||
|
// are supported via this interface.
|
||||||
|
type ClientSessionCache interface {
|
||||||
|
// Get searches for a ClientSessionState associated with the given key.
|
||||||
|
// On return, ok is true if one was found.
|
||||||
|
Get(sessionKey string) (session *ClientSessionState, ok bool)
|
||||||
|
|
||||||
|
// Put adds the ClientSessionState to the cache with the given key. It might
|
||||||
|
// get called multiple times in a connection if a TLS 1.3 server provides
|
||||||
|
// more than one session ticket. If called with a nil *ClientSessionState,
|
||||||
|
// it should remove the cache entry.
|
||||||
|
Put(sessionKey string, cs *ClientSessionState)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:generate stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go
|
||||||
|
|
||||||
|
// SignatureScheme identifies a signature algorithm supported by TLS. See
|
||||||
|
// RFC 8446, Section 4.2.3.
|
||||||
|
type SignatureScheme uint16
|
||||||
|
|
||||||
|
// ClientHelloInfo contains information from a ClientHello message in order to
|
||||||
|
// guide application logic in the GetCertificate and GetConfigForClient callbacks.
|
||||||
|
type ClientHelloInfo struct {
|
||||||
|
// CipherSuites lists the CipherSuites supported by the client (e.g.
|
||||||
|
// TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).
|
||||||
|
CipherSuites []uint16
|
||||||
|
|
||||||
|
// ServerName indicates the name of the server requested by the client
|
||||||
|
// in order to support virtual hosting. ServerName is only set if the
|
||||||
|
// client is using SNI (see RFC 4366, Section 3.1).
|
||||||
|
ServerName string
|
||||||
|
|
||||||
|
// SupportedCurves lists the elliptic curves supported by the client.
|
||||||
|
// SupportedCurves is set only if the Supported Elliptic Curves
|
||||||
|
// Extension is being used (see RFC 4492, Section 5.1.1).
|
||||||
|
SupportedCurves []CurveID
|
||||||
|
|
||||||
|
// SupportedPoints lists the point formats supported by the client.
|
||||||
|
// SupportedPoints is set only if the Supported Point Formats Extension
|
||||||
|
// is being used (see RFC 4492, Section 5.1.2).
|
||||||
|
SupportedPoints []uint8
|
||||||
|
|
||||||
|
// SignatureSchemes lists the signature and hash schemes that the client
|
||||||
|
// is willing to verify. SignatureSchemes is set only if the Signature
|
||||||
|
// Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1).
|
||||||
|
SignatureSchemes []SignatureScheme
|
||||||
|
|
||||||
|
// SupportedProtos lists the application protocols supported by the client.
|
||||||
|
// SupportedProtos is set only if the Application-Layer Protocol
|
||||||
|
// Negotiation Extension is being used (see RFC 7301, Section 3.1).
|
||||||
|
//
|
||||||
|
// Servers can select a protocol by setting Config.NextProtos in a
|
||||||
|
// GetConfigForClient return value.
|
||||||
|
SupportedProtos []string
|
||||||
|
|
||||||
|
// SupportedVersions lists the TLS versions supported by the client.
|
||||||
|
// For TLS versions less than 1.3, this is extrapolated from the max
|
||||||
|
// version advertised by the client, so values other than the greatest
|
||||||
|
// might be rejected if used.
|
||||||
|
SupportedVersions []uint16
|
||||||
|
|
||||||
|
// Conn is the underlying net.Conn for the connection. Do not read
|
||||||
|
// from, or write to, this connection; that will cause the TLS
|
||||||
|
// connection to fail.
|
||||||
|
Conn net.Conn
|
||||||
|
|
||||||
|
// config is embedded by the GetCertificate or GetConfigForClient caller,
|
||||||
|
// for use with SupportsCertificate.
|
||||||
|
config *Config
|
||||||
|
|
||||||
|
// ctx is the context of the handshake that is in progress.
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// CertificateRequestInfo contains information from a server's
|
||||||
|
// CertificateRequest message, which is used to demand a certificate and proof
|
||||||
|
// of control from a client.
|
||||||
|
type CertificateRequestInfo struct {
|
||||||
|
// AcceptableCAs contains zero or more, DER-encoded, X.501
|
||||||
|
// Distinguished Names. These are the names of root or intermediate CAs
|
||||||
|
// that the server wishes the returned certificate to be signed by. An
|
||||||
|
// empty slice indicates that the server has no preference.
|
||||||
|
AcceptableCAs [][]byte
|
||||||
|
|
||||||
|
// SignatureSchemes lists the signature schemes that the server is
|
||||||
|
// willing to verify.
|
||||||
|
SignatureSchemes []SignatureScheme
|
||||||
|
|
||||||
|
// Version is the TLS version that was negotiated for this connection.
|
||||||
|
Version uint16
|
||||||
|
|
||||||
|
// ctx is the context of the handshake that is in progress.
|
||||||
|
ctx context.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenegotiationSupport enumerates the different levels of support for TLS
|
||||||
|
// renegotiation. TLS renegotiation is the act of performing subsequent
|
||||||
|
// handshakes on a connection after the first. This significantly complicates
|
||||||
|
// the state machine and has been the source of numerous, subtle security
|
||||||
|
// issues. Initiating a renegotiation is not supported, but support for
|
||||||
|
// accepting renegotiation requests may be enabled.
|
||||||
|
//
|
||||||
|
// Even when enabled, the server may not change its identity between handshakes
|
||||||
|
// (i.e. the leaf certificate must be the same). Additionally, concurrent
|
||||||
|
// handshake and application data flow is not permitted so renegotiation can
|
||||||
|
// only be used with protocols that synchronise with the renegotiation, such as
|
||||||
|
// HTTPS.
|
||||||
|
//
|
||||||
|
// Renegotiation is not defined in TLS 1.3.
|
||||||
|
type RenegotiationSupport int
|
||||||
|
|
||||||
|
// A Config structure is used to configure a TLS client or server.
|
||||||
|
// After one has been passed to a TLS function it must not be
|
||||||
|
// modified. A Config may be reused; the tls package will also not
|
||||||
|
// modify it.
|
||||||
|
type Config struct {
|
||||||
|
// Rand provides the source of entropy for nonces and RSA blinding.
|
||||||
|
// If Rand is nil, TLS uses the cryptographic random reader in package
|
||||||
|
// crypto/rand.
|
||||||
|
// The Reader must be safe for use by multiple goroutines.
|
||||||
|
Rand io.Reader
|
||||||
|
|
||||||
|
// Time returns the current time as the number of seconds since the epoch.
|
||||||
|
// If Time is nil, TLS uses time.Now.
|
||||||
|
Time func() time.Time
|
||||||
|
|
||||||
|
// Certificates contains one or more certificate chains to present to the
|
||||||
|
// other side of the connection. The first certificate compatible with the
|
||||||
|
// peer's requirements is selected automatically.
|
||||||
|
//
|
||||||
|
// Server configurations must set one of Certificates, GetCertificate or
|
||||||
|
// GetConfigForClient. Clients doing client-authentication may set either
|
||||||
|
// Certificates or GetClientCertificate.
|
||||||
|
//
|
||||||
|
// Note: if there are multiple Certificates, and they don't have the
|
||||||
|
// optional field Leaf set, certificate selection will incur a significant
|
||||||
|
// per-handshake performance cost.
|
||||||
|
Certificates []Certificate
|
||||||
|
|
||||||
|
// NameToCertificate maps from a certificate name to an element of
|
||||||
|
// Certificates. Note that a certificate name can be of the form
|
||||||
|
// '*.example.com' and so doesn't have to be a domain name as such.
|
||||||
|
//
|
||||||
|
// Deprecated: NameToCertificate only allows associating a single
|
||||||
|
// certificate with a given name. Leave this field nil to let the library
|
||||||
|
// select the first compatible chain from Certificates.
|
||||||
|
NameToCertificate map[string]*Certificate
|
||||||
|
|
||||||
|
// GetCertificate returns a Certificate based on the given
|
||||||
|
// ClientHelloInfo. It will only be called if the client supplies SNI
|
||||||
|
// information or if Certificates is empty.
|
||||||
|
//
|
||||||
|
// If GetCertificate is nil or returns nil, then the certificate is
|
||||||
|
// retrieved from NameToCertificate. If NameToCertificate is nil, the
|
||||||
|
// best element of Certificates will be used.
|
||||||
|
//
|
||||||
|
// Once a Certificate is returned it should not be modified.
|
||||||
|
GetCertificate func(*ClientHelloInfo) (*Certificate, error)
|
||||||
|
|
||||||
|
// GetClientCertificate, if not nil, is called when a server requests a
|
||||||
|
// certificate from a client. If set, the contents of Certificates will
|
||||||
|
// be ignored.
|
||||||
|
//
|
||||||
|
// If GetClientCertificate returns an error, the handshake will be
|
||||||
|
// aborted and that error will be returned. Otherwise
|
||||||
|
// GetClientCertificate must return a non-nil Certificate. If
|
||||||
|
// Certificate.Certificate is empty then no certificate will be sent to
|
||||||
|
// the server. If this is unacceptable to the server then it may abort
|
||||||
|
// the handshake.
|
||||||
|
//
|
||||||
|
// GetClientCertificate may be called multiple times for the same
|
||||||
|
// connection if renegotiation occurs or if TLS 1.3 is in use.
|
||||||
|
//
|
||||||
|
// Once a Certificate is returned it should not be modified.
|
||||||
|
GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
|
||||||
|
|
||||||
|
// GetConfigForClient, if not nil, is called after a ClientHello is
|
||||||
|
// received from a client. It may return a non-nil Config in order to
|
||||||
|
// change the Config that will be used to handle this connection. If
|
||||||
|
// the returned Config is nil, the original Config will be used. The
|
||||||
|
// Config returned by this callback may not be subsequently modified.
|
||||||
|
//
|
||||||
|
// If GetConfigForClient is nil, the Config passed to Server() will be
|
||||||
|
// used for all connections.
|
||||||
|
//
|
||||||
|
// If SessionTicketKey was explicitly set on the returned Config, or if
|
||||||
|
// SetSessionTicketKeys was called on the returned Config, those keys will
|
||||||
|
// be used. Otherwise, the original Config keys will be used (and possibly
|
||||||
|
// rotated if they are automatically managed).
|
||||||
|
GetConfigForClient func(*ClientHelloInfo) (*Config, error)
|
||||||
|
|
||||||
|
// VerifyPeerCertificate, if not nil, is called after normal
|
||||||
|
// certificate verification by either a TLS client or server. It
|
||||||
|
// receives the raw ASN.1 certificates provided by the peer and also
|
||||||
|
// any verified chains that normal processing found. If it returns a
|
||||||
|
// non-nil error, the handshake is aborted and that error results.
|
||||||
|
//
|
||||||
|
// If normal verification fails then the handshake will abort before
|
||||||
|
// considering this callback. If normal verification is disabled (on the
|
||||||
|
// client when InsecureSkipVerify is set, or on a server when ClientAuth is
|
||||||
|
// RequestClientCert or RequireAnyClientCert), then this callback will be
|
||||||
|
// considered but the verifiedChains argument will always be nil. When
|
||||||
|
// ClientAuth is NoClientCert, this callback is not called on the server.
|
||||||
|
// rawCerts may be empty on the server if ClientAuth is RequestClientCert or
|
||||||
|
// VerifyClientCertIfGiven.
|
||||||
|
//
|
||||||
|
// This callback is not invoked on resumed connections, as certificates are
|
||||||
|
// not re-verified on resumption.
|
||||||
|
//
|
||||||
|
// verifiedChains and its contents should not be modified.
|
||||||
|
VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
|
||||||
|
|
||||||
|
// VerifyConnection, if not nil, is called after normal certificate
|
||||||
|
// verification and after VerifyPeerCertificate by either a TLS client
|
||||||
|
// or server. If it returns a non-nil error, the handshake is aborted
|
||||||
|
// and that error results.
|
||||||
|
//
|
||||||
|
// If normal verification fails then the handshake will abort before
|
||||||
|
// considering this callback. This callback will run for all connections,
|
||||||
|
// including resumptions, regardless of InsecureSkipVerify or ClientAuth
|
||||||
|
// settings.
|
||||||
|
VerifyConnection func(ConnectionState) error
|
||||||
|
|
||||||
|
// RootCAs defines the set of root certificate authorities
|
||||||
|
// that clients use when verifying server certificates.
|
||||||
|
// If RootCAs is nil, TLS uses the host's root CA set.
|
||||||
|
RootCAs *x509.CertPool
|
||||||
|
|
||||||
|
// NextProtos is a list of supported application level protocols, in
|
||||||
|
// order of preference. If both peers support ALPN, the selected
|
||||||
|
// protocol will be one from this list, and the connection will fail
|
||||||
|
// if there is no mutually supported protocol. If NextProtos is empty
|
||||||
|
// or the peer doesn't support ALPN, the connection will succeed and
|
||||||
|
// ConnectionState.NegotiatedProtocol will be empty.
|
||||||
|
NextProtos []string
|
||||||
|
|
||||||
|
// ServerName is used to verify the hostname on the returned
|
||||||
|
// certificates unless InsecureSkipVerify is given. It is also included
|
||||||
|
// in the client's handshake to support virtual hosting unless it is
|
||||||
|
// an IP address.
|
||||||
|
ServerName string
|
||||||
|
|
||||||
|
// ClientAuth determines the server's policy for
|
||||||
|
// TLS Client Authentication. The default is NoClientCert.
|
||||||
|
ClientAuth ClientAuthType
|
||||||
|
|
||||||
|
// ClientCAs defines the set of root certificate authorities
|
||||||
|
// that servers use if required to verify a client certificate
|
||||||
|
// by the policy in ClientAuth.
|
||||||
|
ClientCAs *x509.CertPool
|
||||||
|
|
||||||
|
// InsecureSkipVerify controls whether a client verifies the server's
|
||||||
|
// certificate chain and host name. If InsecureSkipVerify is true, crypto/tls
|
||||||
|
// accepts any certificate presented by the server and any host name in that
|
||||||
|
// certificate. In this mode, TLS is susceptible to machine-in-the-middle
|
||||||
|
// attacks unless custom verification is used. This should be used only for
|
||||||
|
// testing or in combination with VerifyConnection or VerifyPeerCertificate.
|
||||||
|
InsecureSkipVerify bool
|
||||||
|
|
||||||
|
// CipherSuites is a list of enabled TLS 1.0–1.2 cipher suites. The order of
|
||||||
|
// the list is ignored. Note that TLS 1.3 ciphersuites are not configurable.
|
||||||
|
//
|
||||||
|
// If CipherSuites is nil, a safe default list is used. The default cipher
|
||||||
|
// suites might change over time.
|
||||||
|
CipherSuites []uint16
|
||||||
|
|
||||||
|
// PreferServerCipherSuites is a legacy field and has no effect.
|
||||||
|
//
|
||||||
|
// It used to control whether the server would follow the client's or the
|
||||||
|
// server's preference. Servers now select the best mutually supported
|
||||||
|
// cipher suite based on logic that takes into account inferred client
|
||||||
|
// hardware, server hardware, and security.
|
||||||
|
//
|
||||||
|
// Deprecated: PreferServerCipherSuites is ignored.
|
||||||
|
PreferServerCipherSuites bool
|
||||||
|
|
||||||
|
// SessionTicketsDisabled may be set to true to disable session ticket and
|
||||||
|
// PSK (resumption) support. Note that on clients, session ticket support is
|
||||||
|
// also disabled if ClientSessionCache is nil.
|
||||||
|
SessionTicketsDisabled bool
|
||||||
|
|
||||||
|
// SessionTicketKey is used by TLS servers to provide session resumption.
|
||||||
|
// See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled
|
||||||
|
// with random data before the first server handshake.
|
||||||
|
//
|
||||||
|
// Deprecated: if this field is left at zero, session ticket keys will be
|
||||||
|
// automatically rotated every day and dropped after seven days. For
|
||||||
|
// customizing the rotation schedule or synchronizing servers that are
|
||||||
|
// terminating connections for the same host, use SetSessionTicketKeys.
|
||||||
|
SessionTicketKey [32]byte
|
||||||
|
|
||||||
|
// ClientSessionCache is a cache of ClientSessionState entries for TLS
|
||||||
|
// session resumption. It is only used by clients.
|
||||||
|
ClientSessionCache ClientSessionCache
|
||||||
|
|
||||||
|
// UnwrapSession is called on the server to turn a ticket/identity
|
||||||
|
// previously produced by [WrapSession] into a usable session.
|
||||||
|
//
|
||||||
|
// UnwrapSession will usually either decrypt a session state in the ticket
|
||||||
|
// (for example with [Config.EncryptTicket]), or use the ticket as a handle
|
||||||
|
// to recover a previously stored state. It must use [ParseSessionState] to
|
||||||
|
// deserialize the session state.
|
||||||
|
//
|
||||||
|
// If UnwrapSession returns an error, the connection is terminated. If it
|
||||||
|
// returns (nil, nil), the session is ignored. crypto/tls may still choose
|
||||||
|
// not to resume the returned session.
|
||||||
|
UnwrapSession func(identity []byte, cs ConnectionState) (*SessionState, error)
|
||||||
|
|
||||||
|
// WrapSession is called on the server to produce a session ticket/identity.
|
||||||
|
//
|
||||||
|
// WrapSession must serialize the session state with [SessionState.Bytes].
|
||||||
|
// It may then encrypt the serialized state (for example with
|
||||||
|
// [Config.DecryptTicket]) and use it as the ticket, or store the state and
|
||||||
|
// return a handle for it.
|
||||||
|
//
|
||||||
|
// If WrapSession returns an error, the connection is terminated.
|
||||||
|
//
|
||||||
|
// Warning: the return value will be exposed on the wire and to clients in
|
||||||
|
// plaintext. The application is in charge of encrypting and authenticating
|
||||||
|
// it (and rotating keys) or returning high-entropy identifiers. Failing to
|
||||||
|
// do so correctly can compromise current, previous, and future connections
|
||||||
|
// depending on the protocol version.
|
||||||
|
WrapSession func(ConnectionState, *SessionState) ([]byte, error)
|
||||||
|
|
||||||
|
// MinVersion contains the minimum TLS version that is acceptable.
|
||||||
|
//
|
||||||
|
// By default, TLS 1.2 is currently used as the minimum when acting as a
|
||||||
|
// client, and TLS 1.0 when acting as a server. TLS 1.0 is the minimum
|
||||||
|
// supported by this package, both as a client and as a server.
|
||||||
|
//
|
||||||
|
// The client-side default can temporarily be reverted to TLS 1.0 by
|
||||||
|
// including the value "x509sha1=1" in the GODEBUG environment variable.
|
||||||
|
// Note that this option will be removed in Go 1.19 (but it will still be
|
||||||
|
// possible to set this field to VersionTLS10 explicitly).
|
||||||
|
MinVersion uint16
|
||||||
|
|
||||||
|
// MaxVersion contains the maximum TLS version that is acceptable.
|
||||||
|
//
|
||||||
|
// By default, the maximum version supported by this package is used,
|
||||||
|
// which is currently TLS 1.3.
|
||||||
|
MaxVersion uint16
|
||||||
|
|
||||||
|
// CurvePreferences contains the elliptic curves that will be used in
|
||||||
|
// an ECDHE handshake, in preference order. If empty, the default will
|
||||||
|
// be used. The client will use the first preference as the type for
|
||||||
|
// its key share in TLS 1.3. This may change in the future.
|
||||||
|
CurvePreferences []CurveID
|
||||||
|
|
||||||
|
// DynamicRecordSizingDisabled disables adaptive sizing of TLS records.
|
||||||
|
// When true, the largest possible TLS record size is always used. When
|
||||||
|
// false, the size of TLS records may be adjusted in an attempt to
|
||||||
|
// improve latency.
|
||||||
|
DynamicRecordSizingDisabled bool
|
||||||
|
|
||||||
|
// Renegotiation controls what types of renegotiation are supported.
|
||||||
|
// The default, none, is correct for the vast majority of applications.
|
||||||
|
Renegotiation RenegotiationSupport
|
||||||
|
|
||||||
|
// KeyLogWriter optionally specifies a destination for TLS master secrets
|
||||||
|
// in NSS key log format that can be used to allow external programs
|
||||||
|
// such as Wireshark to decrypt TLS connections.
|
||||||
|
// See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
|
||||||
|
// Use of KeyLogWriter compromises security and should only be
|
||||||
|
// used for debugging.
|
||||||
|
KeyLogWriter io.Writer
|
||||||
|
|
||||||
|
// mutex protects sessionTicketKeys and autoSessionTicketKeys.
|
||||||
|
mutex sync.RWMutex
|
||||||
|
// sessionTicketKeys contains zero or more ticket keys. If set, it means
|
||||||
|
// the keys were set with SessionTicketKey or SetSessionTicketKeys. The
|
||||||
|
// first key is used for new tickets and any subsequent keys can be used to
|
||||||
|
// decrypt old tickets. The slice contents are not protected by the mutex
|
||||||
|
// and are immutable.
|
||||||
|
sessionTicketKeys []ticketKey
|
||||||
|
// autoSessionTicketKeys is like sessionTicketKeys but is owned by the
|
||||||
|
// auto-rotation logic. See Config.ticketKeys.
|
||||||
|
autoSessionTicketKeys []ticketKey
|
||||||
|
}
|
||||||
|
|
||||||
|
// ticketKey is the internal representation of a session ticket key.
|
||||||
|
type ticketKey struct {
|
||||||
|
aesKey [16]byte
|
||||||
|
hmacKey [16]byte
|
||||||
|
// created is the time at which this ticket key was created. See Config.ticketKeys.
|
||||||
|
created time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Certificate is a chain of one or more certificates, leaf first.
|
||||||
|
type Certificate struct {
|
||||||
|
Certificate [][]byte
|
||||||
|
// PrivateKey contains the private key corresponding to the public key in
|
||||||
|
// Leaf. This must implement crypto.Signer with an RSA, ECDSA or Ed25519 PublicKey.
|
||||||
|
// For a server up to TLS 1.2, it can also implement crypto.Decrypter with
|
||||||
|
// an RSA PublicKey.
|
||||||
|
PrivateKey crypto.PrivateKey
|
||||||
|
// SupportedSignatureAlgorithms is an optional list restricting what
|
||||||
|
// signature algorithms the PrivateKey can be used for.
|
||||||
|
SupportedSignatureAlgorithms []SignatureScheme
|
||||||
|
// OCSPStaple contains an optional OCSP response which will be served
|
||||||
|
// to clients that request it.
|
||||||
|
OCSPStaple []byte
|
||||||
|
// SignedCertificateTimestamps contains an optional list of Signed
|
||||||
|
// Certificate Timestamps which will be served to clients that request it.
|
||||||
|
SignedCertificateTimestamps [][]byte
|
||||||
|
// Leaf is the parsed form of the leaf certificate, which may be initialized
|
||||||
|
// using x509.ParseCertificate to reduce per-handshake processing. If nil,
|
||||||
|
// the leaf certificate will be parsed as needed.
|
||||||
|
Leaf *x509.Certificate
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2012 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 tls
|
||||||
|
|
||||||
|
// A SessionState is a resumable session.
|
||||||
|
type SessionState struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientSessionState contains the state needed by a client to
|
||||||
|
// resume a previous TLS session.
|
||||||
|
type ClientSessionState struct {
|
||||||
|
ticket []byte
|
||||||
|
session *SessionState
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
// TINYGO: The following is copied and modified from Go 1.21.4 official implementation.
|
||||||
|
|
||||||
|
// Copyright 2009 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 tls partially implements TLS 1.2, as specified in RFC 5246,
|
||||||
|
// and TLS 1.3, as specified in RFC 8446.
|
||||||
|
package tls
|
||||||
|
|
||||||
|
// BUG(agl): The crypto/tls package only implements some countermeasures
|
||||||
|
// against Lucky13 attacks on CBC-mode encryption, and only on SHA1
|
||||||
|
// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
|
||||||
|
// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Client returns a new TLS client side connection
|
||||||
|
// using conn as the underlying transport.
|
||||||
|
// The config cannot be nil: users must set either ServerName or
|
||||||
|
// InsecureSkipVerify in the config.
|
||||||
|
func Client(conn net.Conn, config *Config) *net.TLSConn {
|
||||||
|
panic("tls.Client() not implemented")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A listener implements a network listener (net.Listener) for TLS connections.
|
||||||
|
type listener struct {
|
||||||
|
net.Listener
|
||||||
|
config *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewListener creates a Listener which accepts connections from an inner
|
||||||
|
// Listener and wraps each connection with Server.
|
||||||
|
// The configuration config must be non-nil and must include
|
||||||
|
// at least one certificate or else set GetCertificate.
|
||||||
|
func NewListener(inner net.Listener, config *Config) net.Listener {
|
||||||
|
l := new(listener)
|
||||||
|
l.Listener = inner
|
||||||
|
l.config = config
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialWithDialer connects to the given network address using dialer.Dial and
|
||||||
|
// then initiates a TLS handshake, returning the resulting TLS connection. Any
|
||||||
|
// timeout or deadline given in the dialer apply to connection and TLS
|
||||||
|
// handshake as a whole.
|
||||||
|
//
|
||||||
|
// DialWithDialer interprets a nil configuration as equivalent to the zero
|
||||||
|
// configuration; see the documentation of Config for the defaults.
|
||||||
|
//
|
||||||
|
// DialWithDialer uses context.Background internally; to specify the context,
|
||||||
|
// use Dialer.DialContext with NetDialer set to the desired dialer.
|
||||||
|
func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*net.TLSConn, error) {
|
||||||
|
switch network {
|
||||||
|
case "tcp", "tcp4":
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("Network %s not supported", network)
|
||||||
|
}
|
||||||
|
|
||||||
|
return net.DialTLS(addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial connects to the given network address using net.Dial
|
||||||
|
// and then initiates a TLS handshake, returning the resulting
|
||||||
|
// TLS connection.
|
||||||
|
// Dial interprets a nil configuration as equivalent to
|
||||||
|
// the zero configuration; see the documentation of Config
|
||||||
|
// for the defaults.
|
||||||
|
func Dial(network, addr string, config *Config) (*net.TLSConn, error) {
|
||||||
|
return DialWithDialer(new(net.Dialer), network, addr, config)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dialer dials TLS connections given a configuration and a Dialer for the
|
||||||
|
// underlying connection.
|
||||||
|
type Dialer struct {
|
||||||
|
// NetDialer is the optional dialer to use for the TLS connections'
|
||||||
|
// underlying TCP connections.
|
||||||
|
// A nil NetDialer is equivalent to the net.Dialer zero value.
|
||||||
|
NetDialer *net.Dialer
|
||||||
|
|
||||||
|
// Config is the TLS configuration to use for new connections.
|
||||||
|
// A nil configuration is equivalent to the zero
|
||||||
|
// configuration; see the documentation of Config for the
|
||||||
|
// defaults.
|
||||||
|
Config *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// DialContext connects to the given network address and initiates a TLS
|
||||||
|
// handshake, returning the resulting TLS connection.
|
||||||
|
//
|
||||||
|
// The provided Context must be non-nil. If the context expires before
|
||||||
|
// the connection is complete, an error is returned. Once successfully
|
||||||
|
// connected, any expiration of the context will not affect the
|
||||||
|
// connection.
|
||||||
|
//
|
||||||
|
// The returned Conn, if any, will always be of type *Conn.
|
||||||
|
func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
return nil, errors.New("tls:DialContext not implmented")
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadX509KeyPair reads and parses a public/private key pair from a pair
|
||||||
|
// of files. The files must contain PEM encoded data. The certificate file
|
||||||
|
// may contain intermediate certificates following the leaf certificate to
|
||||||
|
// form a certificate chain. On successful return, Certificate.Leaf will
|
||||||
|
// be nil because the parsed form of the certificate is not retained.
|
||||||
|
func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
|
||||||
|
return Certificate{}, errors.New("tls:LoadX509KeyPair not implemented")
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// this is intended to be used as wasm32-unknown-unknown module.
|
||||||
|
// to compile it, run:
|
||||||
|
// tinygo build -size short -o hello-unknown.wasm -target wasm-unknown -gc=leaking -no-debug ./src/examples/hello-wasm-unknown/
|
||||||
|
package main
|
||||||
|
|
||||||
|
var x int32
|
||||||
|
|
||||||
|
//go:wasmimport hosted echo_i32
|
||||||
|
func echo(x int32)
|
||||||
|
|
||||||
|
//go:export update
|
||||||
|
func update() {
|
||||||
|
x++
|
||||||
|
echo(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// to override the USB Manufacturer or Product names:
|
// to override the USB Manufacturer or Product names:
|
||||||
//
|
//
|
||||||
// tinygo flash -target circuitplay-express -ldflags="-X main.usbManufacturer='TinyGopher Labs' -X main.usbProduct='GopherKeyboard'" examples/hid-keyboard
|
// tinygo flash -target circuitplay-express -ldflags="-X main.usbManufacturer='TinyGopher Labs' -X main.usbProduct='GopherKeyboard' -X main.usbSerial='XXXXX'" examples/hid-keyboard
|
||||||
//
|
//
|
||||||
// you can also override the VID/PID. however, only set this if you know what you are doing,
|
// you can also override the VID/PID. however, only set this if you know what you are doing,
|
||||||
// since changing it can make it difficult to reflash some devices.
|
// since changing it can make it difficult to reflash some devices.
|
||||||
@@ -15,7 +15,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var usbVID, usbPID string
|
var usbVID, usbPID string
|
||||||
var usbManufacturer, usbProduct string
|
var usbManufacturer, usbProduct, usbSerial string
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
button := machine.BUTTON
|
button := machine.BUTTON
|
||||||
@@ -49,4 +49,8 @@ func init() {
|
|||||||
if usbProduct != "" {
|
if usbProduct != "" {
|
||||||
usb.Product = usbProduct
|
usb.Product = usbProduct
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if usbSerial != "" {
|
||||||
|
usb.Serial = usbSerial
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
package bytealg
|
package bytealg
|
||||||
|
|
||||||
|
// Some code in this file has been copied from the Go source code, and has
|
||||||
|
// copyright of their original authors:
|
||||||
|
//
|
||||||
|
// Copyright 2020 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.
|
||||||
|
//
|
||||||
|
// This is indicated specifically in the file.
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Index can search any valid length of string.
|
// Index can search any valid length of string.
|
||||||
|
|
||||||
@@ -125,10 +134,6 @@ func IndexString(str, sub string) int {
|
|||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copyright 2020 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.
|
|
||||||
|
|
||||||
// The following code has been copied from the Go 1.15 release tree.
|
// The following code has been copied from the Go 1.15 release tree.
|
||||||
|
|
||||||
// PrimeRK is the prime base used in Rabin-Karp algorithm.
|
// PrimeRK is the prime base used in Rabin-Karp algorithm.
|
||||||
@@ -136,6 +141,8 @@ const PrimeRK = 16777619
|
|||||||
|
|
||||||
// HashStrBytes returns the hash and the appropriate multiplicative
|
// HashStrBytes returns the hash and the appropriate multiplicative
|
||||||
// factor for use in Rabin-Karp algorithm.
|
// factor for use in Rabin-Karp algorithm.
|
||||||
|
//
|
||||||
|
// This function was removed in Go 1.22.
|
||||||
func HashStrBytes(sep []byte) (uint32, uint32) {
|
func HashStrBytes(sep []byte) (uint32, uint32) {
|
||||||
hash := uint32(0)
|
hash := uint32(0)
|
||||||
for i := 0; i < len(sep); i++ {
|
for i := 0; i < len(sep); i++ {
|
||||||
@@ -153,7 +160,9 @@ func HashStrBytes(sep []byte) (uint32, uint32) {
|
|||||||
|
|
||||||
// HashStr returns the hash and the appropriate multiplicative
|
// HashStr returns the hash and the appropriate multiplicative
|
||||||
// factor for use in Rabin-Karp algorithm.
|
// factor for use in Rabin-Karp algorithm.
|
||||||
func HashStr(sep string) (uint32, uint32) {
|
//
|
||||||
|
// This function was removed in Go 1.22.
|
||||||
|
func HashStr[T string | []byte](sep T) (uint32, uint32) {
|
||||||
hash := uint32(0)
|
hash := uint32(0)
|
||||||
for i := 0; i < len(sep); i++ {
|
for i := 0; i < len(sep); i++ {
|
||||||
hash = hash*PrimeRK + uint32(sep[i])
|
hash = hash*PrimeRK + uint32(sep[i])
|
||||||
@@ -170,6 +179,8 @@ func HashStr(sep string) (uint32, uint32) {
|
|||||||
|
|
||||||
// HashStrRevBytes returns the hash of the reverse of sep and the
|
// HashStrRevBytes returns the hash of the reverse of sep and the
|
||||||
// appropriate multiplicative factor for use in Rabin-Karp algorithm.
|
// appropriate multiplicative factor for use in Rabin-Karp algorithm.
|
||||||
|
//
|
||||||
|
// This function was removed in Go 1.22.
|
||||||
func HashStrRevBytes(sep []byte) (uint32, uint32) {
|
func HashStrRevBytes(sep []byte) (uint32, uint32) {
|
||||||
hash := uint32(0)
|
hash := uint32(0)
|
||||||
for i := len(sep) - 1; i >= 0; i-- {
|
for i := len(sep) - 1; i >= 0; i-- {
|
||||||
@@ -187,7 +198,9 @@ func HashStrRevBytes(sep []byte) (uint32, uint32) {
|
|||||||
|
|
||||||
// HashStrRev returns the hash of the reverse of sep and the
|
// HashStrRev returns the hash of the reverse of sep and the
|
||||||
// appropriate multiplicative factor for use in Rabin-Karp algorithm.
|
// appropriate multiplicative factor for use in Rabin-Karp algorithm.
|
||||||
func HashStrRev(sep string) (uint32, uint32) {
|
//
|
||||||
|
// Copied from the Go 1.22rc1 source tree.
|
||||||
|
func HashStrRev[T string | []byte](sep T) (uint32, uint32) {
|
||||||
hash := uint32(0)
|
hash := uint32(0)
|
||||||
for i := len(sep) - 1; i >= 0; i-- {
|
for i := len(sep) - 1; i >= 0; i-- {
|
||||||
hash = hash*PrimeRK + uint32(sep[i])
|
hash = hash*PrimeRK + uint32(sep[i])
|
||||||
@@ -204,6 +217,8 @@ func HashStrRev(sep string) (uint32, uint32) {
|
|||||||
|
|
||||||
// IndexRabinKarpBytes uses the Rabin-Karp search algorithm to return the index of the
|
// IndexRabinKarpBytes uses the Rabin-Karp search algorithm to return the index of the
|
||||||
// first occurence of substr in s, or -1 if not present.
|
// first occurence of substr in s, or -1 if not present.
|
||||||
|
//
|
||||||
|
// This function was removed in Go 1.22.
|
||||||
func IndexRabinKarpBytes(s, sep []byte) int {
|
func IndexRabinKarpBytes(s, sep []byte) int {
|
||||||
// Rabin-Karp search
|
// Rabin-Karp search
|
||||||
hashsep, pow := HashStrBytes(sep)
|
hashsep, pow := HashStrBytes(sep)
|
||||||
@@ -228,16 +243,18 @@ func IndexRabinKarpBytes(s, sep []byte) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IndexRabinKarp uses the Rabin-Karp search algorithm to return the index of the
|
// IndexRabinKarp uses the Rabin-Karp search algorithm to return the index of the
|
||||||
// first occurence of substr in s, or -1 if not present.
|
// first occurrence of sep in s, or -1 if not present.
|
||||||
func IndexRabinKarp(s, substr string) int {
|
//
|
||||||
|
// Copied from the Go 1.22rc1 source tree.
|
||||||
|
func IndexRabinKarp[T string | []byte](s, sep T) int {
|
||||||
// Rabin-Karp search
|
// Rabin-Karp search
|
||||||
hashss, pow := HashStr(substr)
|
hashss, pow := HashStr(sep)
|
||||||
n := len(substr)
|
n := len(sep)
|
||||||
var h uint32
|
var h uint32
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
h = h*PrimeRK + uint32(s[i])
|
h = h*PrimeRK + uint32(s[i])
|
||||||
}
|
}
|
||||||
if h == hashss && s[:n] == substr {
|
if h == hashss && string(s[:n]) == string(sep) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
for i := n; i < len(s); {
|
for i := n; i < len(s); {
|
||||||
@@ -245,7 +262,7 @@ func IndexRabinKarp(s, substr string) int {
|
|||||||
h += uint32(s[i])
|
h += uint32(s[i])
|
||||||
h -= pow * uint32(s[i-n])
|
h -= pow * uint32(s[i-n])
|
||||||
i++
|
i++
|
||||||
if h == hashss && s[i-n:i] == substr {
|
if h == hashss && string(s[i-n:i]) == string(sep) {
|
||||||
return i - n
|
return i - n
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,3 +278,50 @@ func MakeNoZero(n int) []byte {
|
|||||||
// malloc function implemented in the runtime).
|
// malloc function implemented in the runtime).
|
||||||
return make([]byte, n)
|
return make([]byte, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copied from the Go 1.22rc1 source tree.
|
||||||
|
func LastIndexByte(s []byte, c byte) int {
|
||||||
|
for i := len(s) - 1; i >= 0; i-- {
|
||||||
|
if s[i] == c {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copied from the Go 1.22rc1 source tree.
|
||||||
|
func LastIndexByteString(s string, c byte) int {
|
||||||
|
for i := len(s) - 1; i >= 0; i-- {
|
||||||
|
if s[i] == c {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
// LastIndexRabinKarp uses the Rabin-Karp search algorithm to return the last index of the
|
||||||
|
// occurrence of sep in s, or -1 if not present.
|
||||||
|
//
|
||||||
|
// Copied from the Go 1.22rc1 source tree.
|
||||||
|
func LastIndexRabinKarp[T string | []byte](s, sep T) int {
|
||||||
|
// Rabin-Karp search from the end of the string
|
||||||
|
hashss, pow := HashStrRev(sep)
|
||||||
|
n := len(sep)
|
||||||
|
last := len(s) - n
|
||||||
|
var h uint32
|
||||||
|
for i := len(s) - 1; i >= last; i-- {
|
||||||
|
h = h*PrimeRK + uint32(s[i])
|
||||||
|
}
|
||||||
|
if h == hashss && string(s[last:]) == string(sep) {
|
||||||
|
return last
|
||||||
|
}
|
||||||
|
for i := last - 1; i >= 0; i-- {
|
||||||
|
h *= PrimeRK
|
||||||
|
h += uint32(s[i])
|
||||||
|
h -= pow * uint32(s[i+n])
|
||||||
|
if h == hashss && string(s[i:i+n]) == string(sep) {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build tinygo
|
||||||
|
|
||||||
// Only generate .debug_frame, don't generate .eh_frame.
|
// Only generate .debug_frame, don't generate .eh_frame.
|
||||||
.cfi_sections .debug_frame
|
.cfi_sections .debug_frame
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build tinygo
|
||||||
|
|
||||||
.section .bss.tinygo_systemStack
|
.section .bss.tinygo_systemStack
|
||||||
.global tinygo_systemStack
|
.global tinygo_systemStack
|
||||||
.type tinygo_systemStack, %object
|
.type tinygo_systemStack, %object
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build tinygo
|
||||||
|
|
||||||
// Only generate .debug_frame, don't generate .eh_frame.
|
// Only generate .debug_frame, don't generate .eh_frame.
|
||||||
.cfi_sections .debug_frame
|
.cfi_sections .debug_frame
|
||||||
|
|
||||||
|
|||||||
@@ -52,17 +52,17 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *state) resume() {
|
func (s *state) resume() {
|
||||||
switchToTask(s.sp)
|
tinygo_switchToTask(s.sp)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export tinygo_switchToTask
|
//export tinygo_switchToTask
|
||||||
func switchToTask(uintptr)
|
func tinygo_switchToTask(uintptr)
|
||||||
|
|
||||||
//export tinygo_switchToScheduler
|
//export tinygo_switchToScheduler
|
||||||
func switchToScheduler(*uintptr)
|
func tinygo_switchToScheduler(*uintptr)
|
||||||
|
|
||||||
func (s *state) pause() {
|
func (s *state) pause() {
|
||||||
switchToScheduler(&s.sp)
|
tinygo_switchToScheduler(&s.sp)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SystemStack returns the system stack pointer. On Cortex-M, it is always
|
// SystemStack returns the system stack pointer. On Cortex-M, it is always
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build tinygo
|
||||||
|
|
||||||
.section .text.tinygo_startTask,"ax",@progbits
|
.section .text.tinygo_startTask,"ax",@progbits
|
||||||
.global tinygo_startTask
|
.global tinygo_startTask
|
||||||
.type tinygo_startTask, %function
|
.type tinygo_startTask, %function
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build tinygo
|
||||||
|
|
||||||
.section .text.tinygo_startTask,"ax",@progbits
|
.section .text.tinygo_startTask,"ax",@progbits
|
||||||
.global tinygo_startTask
|
.global tinygo_startTask
|
||||||
.type tinygo_startTask, %function
|
.type tinygo_startTask, %function
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build tinygo
|
||||||
|
|
||||||
.section .text.tinygo_startTask
|
.section .text.tinygo_startTask
|
||||||
.global tinygo_startTask
|
.global tinygo_startTask
|
||||||
.type tinygo_startTask, %function
|
.type tinygo_startTask, %function
|
||||||
|
|||||||
@@ -2,11 +2,6 @@
|
|||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
// Return the current CPU frequency in hertz.
|
|
||||||
func CPUFrequency() uint32 {
|
|
||||||
return 16000000
|
|
||||||
}
|
|
||||||
|
|
||||||
// Digital pins, marked as plain numbers on the board.
|
// Digital pins, marked as plain numbers on the board.
|
||||||
const (
|
const (
|
||||||
D0 = PD0 // RX
|
D0 = PD0 // RX
|
||||||
|
|||||||
@@ -2,11 +2,6 @@
|
|||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
// Return the current CPU frequency in hertz.
|
|
||||||
func CPUFrequency() uint32 {
|
|
||||||
return 16000000
|
|
||||||
}
|
|
||||||
|
|
||||||
// Digital pins.
|
// Digital pins.
|
||||||
const (
|
const (
|
||||||
D0 = PD0 // RX0
|
D0 = PD0 // RX0
|
||||||
|
|||||||
@@ -63,6 +63,9 @@ var UART1 = &sercomUSART3
|
|||||||
// UART2 on the Arduino Nano 33 connects to the normal TX/RX pins.
|
// UART2 on the Arduino Nano 33 connects to the normal TX/RX pins.
|
||||||
var UART2 = &sercomUSART5
|
var UART2 = &sercomUSART5
|
||||||
|
|
||||||
|
// UART_NINA on the Arduino Nano 33 connects to the NINA HCI.
|
||||||
|
var UART_NINA = &sercomUSART2
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN Pin = A4 // SDA: SERCOM4/PAD[1]
|
SDA_PIN Pin = A4 // SDA: SERCOM4/PAD[1]
|
||||||
@@ -99,8 +102,17 @@ const (
|
|||||||
NINA_GPIO0 Pin = PA27
|
NINA_GPIO0 Pin = PA27
|
||||||
NINA_RESETN Pin = PA08
|
NINA_RESETN Pin = PA08
|
||||||
NINA_ACK Pin = PA28
|
NINA_ACK Pin = PA28
|
||||||
NINA_TX Pin = PA22
|
NINA_TX Pin = PA12
|
||||||
NINA_RX Pin = PA23
|
NINA_RX Pin = PA13
|
||||||
|
NINA_RTS Pin = PA14
|
||||||
|
NINA_CTS Pin = PA15
|
||||||
|
)
|
||||||
|
|
||||||
|
// NINA-W102 settings
|
||||||
|
const (
|
||||||
|
NINA_BAUDRATE = 912600
|
||||||
|
NINA_RESET_INVERTED = true
|
||||||
|
NINA_SOFT_FLOWCONTROL = false
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2S pins
|
// I2S pins
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
|
// Return the current CPU frequency in hertz.
|
||||||
|
func CPUFrequency() uint32 {
|
||||||
|
return 16000000
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Note: start at port B because there is no port A.
|
// Note: start at port B because there is no port A.
|
||||||
portB Pin = iota * 8
|
portB Pin = iota * 8
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
//go:build avr && atmega328pb
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
// Return the current CPU frequency in hertz.
|
||||||
|
func CPUFrequency() uint32 {
|
||||||
|
return 16000000
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Note: start at port B because there is no port A.
|
||||||
|
portB Pin = iota * 8
|
||||||
|
portC
|
||||||
|
portD
|
||||||
|
portE
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PB0 = portB + 0
|
||||||
|
PB1 = portB + 1 // peripherals: Timer1 channel A
|
||||||
|
PB2 = portB + 2 // peripherals: Timer1 channel B
|
||||||
|
PB3 = portB + 3 // peripherals: Timer2 channel A
|
||||||
|
PB4 = portB + 4
|
||||||
|
PB5 = portB + 5
|
||||||
|
PB6 = portB + 6
|
||||||
|
PB7 = portB + 7
|
||||||
|
PC0 = portC + 0
|
||||||
|
PC1 = portC + 1
|
||||||
|
PC2 = portC + 2
|
||||||
|
PC3 = portC + 3
|
||||||
|
PC4 = portC + 4
|
||||||
|
PC5 = portC + 5
|
||||||
|
PC6 = portC + 6
|
||||||
|
PC7 = portC + 7
|
||||||
|
PD0 = portD + 0
|
||||||
|
PD1 = portD + 1
|
||||||
|
PD2 = portD + 2
|
||||||
|
PD3 = portD + 3 // peripherals: Timer2 channel B
|
||||||
|
PD4 = portD + 4
|
||||||
|
PD5 = portD + 5 // peripherals: Timer0 channel B
|
||||||
|
PD6 = portD + 6 // peripherals: Timer0 channel A
|
||||||
|
PD7 = portD + 7
|
||||||
|
PE0 = portE + 0
|
||||||
|
PE1 = portE + 1
|
||||||
|
PE2 = portE + 2
|
||||||
|
PE3 = portE + 3
|
||||||
|
PE4 = portE + 4
|
||||||
|
PE5 = portE + 5
|
||||||
|
PE6 = portE + 6
|
||||||
|
PE7 = portE + 7
|
||||||
|
)
|
||||||
@@ -73,7 +73,7 @@ const (
|
|||||||
|
|
||||||
// USB CDC identifiers
|
// USB CDC identifiers
|
||||||
const (
|
const (
|
||||||
usb_STRING_PRODUCT = "Gopher Badger"
|
usb_STRING_PRODUCT = "Gopher Badge"
|
||||||
usb_STRING_MANUFACTURER = "TinyGo"
|
usb_STRING_MANUFACTURER = "TinyGo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -62,6 +62,15 @@ var (
|
|||||||
UART2 = &sercomUSART0
|
UART2 = &sercomUSART0
|
||||||
|
|
||||||
DefaultUART = UART1
|
DefaultUART = UART1
|
||||||
|
|
||||||
|
UART_NINA = UART2
|
||||||
|
)
|
||||||
|
|
||||||
|
// NINA-W102 settings
|
||||||
|
const (
|
||||||
|
NINA_BAUDRATE = 115200
|
||||||
|
NINA_RESET_INVERTED = true
|
||||||
|
NINA_SOFT_FLOWCONTROL = true
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -70,9 +79,12 @@ const (
|
|||||||
NINA_GPIO0 = PB01
|
NINA_GPIO0 = PB01
|
||||||
NINA_RESETN = PB05
|
NINA_RESETN = PB05
|
||||||
|
|
||||||
|
// pins used for the ESP32 connection do not allow hardware
|
||||||
|
// flow control, which is required. have to emulate with software.
|
||||||
NINA_TX = PA04
|
NINA_TX = PA04
|
||||||
NINA_RX = PA07
|
NINA_RX = PA07
|
||||||
NINA_RTS = PB23
|
NINA_CTS = NINA_ACK
|
||||||
|
NINA_RTS = NINA_GPIO0
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
|
|||||||
@@ -0,0 +1,142 @@
|
|||||||
|
//go:build mksnanov3
|
||||||
|
|
||||||
|
// The MKS Robin Nano V3.X board.
|
||||||
|
// Documented at https://github.com/makerbase-mks/MKS-Robin-Nano-V3.X.
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/stm32"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LED is also wired to the SD card card detect (CD) pin.
|
||||||
|
const LED = PD12
|
||||||
|
|
||||||
|
// UART pins
|
||||||
|
const (
|
||||||
|
UART_TX_PIN = PB10
|
||||||
|
UART_RX_PIN = PB11
|
||||||
|
)
|
||||||
|
|
||||||
|
// EXP1 and EXP2 expansion ports for connecting
|
||||||
|
// the MKS TS35 V2.0 expansion board.
|
||||||
|
const (
|
||||||
|
BEEPER = EXP1_1
|
||||||
|
|
||||||
|
// LCD pins.
|
||||||
|
LCD_DC = EXP1_8
|
||||||
|
LCD_CS = EXP1_7
|
||||||
|
LCD_RS = EXP1_4
|
||||||
|
LCD_BACKLIGHT = EXP1_3
|
||||||
|
|
||||||
|
// Touch pins. Note that some pins are shared with the
|
||||||
|
// LCD SPI1 interface.
|
||||||
|
TOUCH_CLK = EXP2_2
|
||||||
|
TOUCH_CS = EXP1_5
|
||||||
|
TOUCH_DIN = EXP2_6
|
||||||
|
TOUCH_DOUT = EXP2_1
|
||||||
|
TOUCH_IRQ = EXP1_6
|
||||||
|
|
||||||
|
BUTTON = BUTTON_JOG
|
||||||
|
BUTTON_JOG = EXP1_2
|
||||||
|
BUTTON_JOG_CCW = EXP2_3
|
||||||
|
BUTTON_JOG_CW = EXP2_5
|
||||||
|
|
||||||
|
EXP1_1 = PC5
|
||||||
|
EXP1_2 = PE13
|
||||||
|
EXP1_3 = PD13
|
||||||
|
EXP1_4 = PC6
|
||||||
|
EXP1_5 = PE14
|
||||||
|
EXP1_6 = PE15
|
||||||
|
EXP1_7 = PD11
|
||||||
|
EXP1_8 = PD10
|
||||||
|
|
||||||
|
EXP2_1 = PA6
|
||||||
|
EXP2_2 = PA5
|
||||||
|
EXP2_3 = PE8
|
||||||
|
EXP2_4 = PE10
|
||||||
|
EXP2_5 = PE11
|
||||||
|
EXP2_6 = PA7
|
||||||
|
EXP2_7 = PE12
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UART3 = &_UART3
|
||||||
|
_UART3 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: stm32.USART3,
|
||||||
|
TxAltFuncSelector: AF7_USART1_2_3,
|
||||||
|
RxAltFuncSelector: AF7_USART1_2_3,
|
||||||
|
}
|
||||||
|
DefaultUART = UART3
|
||||||
|
)
|
||||||
|
|
||||||
|
// set up RX IRQ handler. Follow similar pattern for other UARTx instances
|
||||||
|
func init() {
|
||||||
|
UART3.Interrupt = interrupt.New(stm32.IRQ_USART3, _UART3.handleInterrupt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
const (
|
||||||
|
SPI1_SCK_PIN = EXP2_2
|
||||||
|
SPI1_SDI_PIN = EXP2_1
|
||||||
|
SPI1_SDO_PIN = EXP2_6
|
||||||
|
SPI0_SCK_PIN = SPI1_SCK_PIN
|
||||||
|
SPI0_SDI_PIN = SPI1_SDI_PIN
|
||||||
|
SPI0_SDO_PIN = SPI1_SDO_PIN
|
||||||
|
)
|
||||||
|
|
||||||
|
// Since the first interface is named SPI1, both SPI0 and SPI1 refer to SPI1.
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{
|
||||||
|
Bus: stm32.SPI1,
|
||||||
|
AltFuncSelector: AF5_SPI1_SPI2,
|
||||||
|
}
|
||||||
|
SPI1 = &SPI0
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
I2C0_SCL_PIN = PB6
|
||||||
|
I2C0_SDA_PIN = PB7
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
I2C0 = &I2C{
|
||||||
|
Bus: stm32.I2C1,
|
||||||
|
AltFuncSelector: AF4_I2C1_2_3,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// Motor control pins.
|
||||||
|
const (
|
||||||
|
X_ENABLE = PE4
|
||||||
|
X_STEP = PE3
|
||||||
|
X_DIR = PE2
|
||||||
|
X_DIAG = PA15
|
||||||
|
X_UART = PD5
|
||||||
|
|
||||||
|
Y_ENABLE = PE1
|
||||||
|
Y_STEP = PE0
|
||||||
|
Y_DIR = PB9
|
||||||
|
Y_DIAG = PD2
|
||||||
|
Y_UART = PD7
|
||||||
|
|
||||||
|
Z_ENABLE = PB8
|
||||||
|
Z_STEP = PB5
|
||||||
|
Z_DIR = PB4
|
||||||
|
Z_DIAG = PC8
|
||||||
|
Z_UART = PD4
|
||||||
|
|
||||||
|
E0_ENABLE = PB3
|
||||||
|
E0_STEP = PD6
|
||||||
|
E0_DIR = PD3
|
||||||
|
E0_DIAG = PC4
|
||||||
|
E0_UART = PD9
|
||||||
|
|
||||||
|
E1_ENABLE = PA3
|
||||||
|
E1_STEP = PD15
|
||||||
|
E1_DIR = PA1
|
||||||
|
E1_DIAG = PE7
|
||||||
|
E1_UART = PD8
|
||||||
|
)
|
||||||
@@ -87,8 +87,17 @@ const (
|
|||||||
NINA_GPIO0 Pin = GPIO2
|
NINA_GPIO0 Pin = GPIO2
|
||||||
NINA_RESETN Pin = GPIO3
|
NINA_RESETN Pin = GPIO3
|
||||||
|
|
||||||
NINA_TX Pin = GPIO9
|
NINA_TX Pin = GPIO8
|
||||||
NINA_RX Pin = GPIO8
|
NINA_RX Pin = GPIO9
|
||||||
|
NINA_CTS Pin = GPIO10
|
||||||
|
NINA_RTS Pin = GPIO11
|
||||||
|
)
|
||||||
|
|
||||||
|
// NINA-W102 settings
|
||||||
|
const (
|
||||||
|
NINA_BAUDRATE = 115200
|
||||||
|
NINA_RESET_INVERTED = true
|
||||||
|
NINA_SOFT_FLOWCONTROL = false
|
||||||
)
|
)
|
||||||
|
|
||||||
// Onboard crystal oscillator frequency, in MHz.
|
// Onboard crystal oscillator frequency, in MHz.
|
||||||
@@ -123,10 +132,20 @@ var (
|
|||||||
Buffer: NewRingBuffer(),
|
Buffer: NewRingBuffer(),
|
||||||
Bus: rp.UART0,
|
Bus: rp.UART0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UART1 = &_UART1
|
||||||
|
_UART1 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: rp.UART1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// UART_NINA on the Arduino Nano RP2040 connects to the NINA HCI.
|
||||||
|
UART_NINA = UART1
|
||||||
)
|
)
|
||||||
|
|
||||||
var DefaultUART = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||||
|
UART1.Interrupt = interrupt.New(rp.IRQ_UART1_IRQ, _UART1.handleInterrupt)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
//go:build nrf52840 && nrf52840_generic
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
var (
|
||||||
|
LED = NoPin
|
||||||
|
SDA_PIN = NoPin
|
||||||
|
SCL_PIN = NoPin
|
||||||
|
UART_TX_PIN = NoPin
|
||||||
|
UART_RX_PIN = NoPin
|
||||||
|
SPI0_SCK_PIN = NoPin
|
||||||
|
SPI0_SDO_PIN = NoPin
|
||||||
|
SPI0_SDI_PIN = NoPin
|
||||||
|
|
||||||
|
// https://pid.codes/org/TinyGo/
|
||||||
|
usb_VID uint16 = 0x1209
|
||||||
|
usb_PID uint16 = 0x9090
|
||||||
|
|
||||||
|
usb_STRING_MANUFACTURER = "TinyGo"
|
||||||
|
usb_STRING_PRODUCT = "nRF52840 Generic board"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultUART = UART0
|
||||||
|
)
|
||||||
@@ -130,3 +130,33 @@ var (
|
|||||||
usb_VID uint16 = 0x239A
|
usb_VID uint16 = 0x239A
|
||||||
usb_PID uint16 = 0x8033
|
usb_PID uint16 = 0x8033
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NINA-W102 settings when using AirLift WiFi FeatherWing
|
||||||
|
const (
|
||||||
|
NINA_BAUDRATE = 115200
|
||||||
|
NINA_RESET_INVERTED = true
|
||||||
|
NINA_SOFT_FLOWCONTROL = true
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
NINA_CS = D13
|
||||||
|
NINA_ACK = D11
|
||||||
|
NINA_GPIO0 = D10
|
||||||
|
NINA_RESETN = D12
|
||||||
|
|
||||||
|
// pins used for the ESP32 connection do not allow hardware
|
||||||
|
// flow control, which is required. have to emulate with software.
|
||||||
|
NINA_TX = UART_TX_PIN
|
||||||
|
NINA_RX = UART_RX_PIN
|
||||||
|
NINA_CTS = NINA_ACK
|
||||||
|
NINA_RTS = NINA_GPIO0
|
||||||
|
|
||||||
|
NINA_SDO = SPI0_SDO_PIN
|
||||||
|
NINA_SDI = SPI0_SDI_PIN
|
||||||
|
NINA_SCK = SPI0_SCK_PIN
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
NINA_SPI = SPI0
|
||||||
|
UART_NINA = UART1
|
||||||
|
)
|
||||||
|
|||||||
@@ -53,9 +53,12 @@ const (
|
|||||||
NINA_GPIO0 = D6
|
NINA_GPIO0 = D6
|
||||||
NINA_RESETN = D7
|
NINA_RESETN = D7
|
||||||
|
|
||||||
|
// pins used for the ESP32 connection do not allow hardware
|
||||||
|
// flow control, which is required. have to emulate with software.
|
||||||
NINA_TX = D1
|
NINA_TX = D1
|
||||||
NINA_RX = D0
|
NINA_RX = D0
|
||||||
NINA_RTS = D51
|
NINA_CTS = NINA_ACK
|
||||||
|
NINA_RTS = NINA_GPIO0
|
||||||
|
|
||||||
LCD_DATA0 = D34
|
LCD_DATA0 = D34
|
||||||
|
|
||||||
@@ -111,6 +114,15 @@ var (
|
|||||||
UART1 = &sercomUSART4
|
UART1 = &sercomUSART4
|
||||||
|
|
||||||
DefaultUART = UART1
|
DefaultUART = UART1
|
||||||
|
|
||||||
|
UART_NINA = UART1
|
||||||
|
)
|
||||||
|
|
||||||
|
// NINA-W102 settings
|
||||||
|
const (
|
||||||
|
NINA_BAUDRATE = 115200
|
||||||
|
NINA_RESET_INVERTED = true
|
||||||
|
NINA_SOFT_FLOWCONTROL = true
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
//go:build qtpy_esp32c3
|
||||||
|
|
||||||
|
// This file contains the pin mappings for the Adafruit QtPy ESP32C3 boards.
|
||||||
|
//
|
||||||
|
// https://learn.adafruit.com/adafruit-qt-py-esp32-c3-wifi-dev-board/pinouts
|
||||||
|
package machine
|
||||||
|
|
||||||
|
// Digital Pins
|
||||||
|
const (
|
||||||
|
D0 = GPIO4
|
||||||
|
D1 = GPIO3
|
||||||
|
D2 = GPIO1
|
||||||
|
D3 = GPIO0
|
||||||
|
)
|
||||||
|
|
||||||
|
// Analog pins (ADC1)
|
||||||
|
const (
|
||||||
|
A0 = GPIO4
|
||||||
|
A1 = GPIO3
|
||||||
|
A2 = GPIO1
|
||||||
|
A3 = GPIO0
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART pins
|
||||||
|
const (
|
||||||
|
RX_PIN = GPIO20
|
||||||
|
TX_PIN = GPIO21
|
||||||
|
|
||||||
|
UART_RX_PIN = RX_PIN
|
||||||
|
UART_TX_PIN = TX_PIN
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C pins
|
||||||
|
const (
|
||||||
|
SDA_PIN = GPIO5
|
||||||
|
SCL_PIN = GPIO6
|
||||||
|
|
||||||
|
I2C0_SDA_PIN = SDA_PIN
|
||||||
|
I2C0_SCL_PIN = SCL_PIN
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
const (
|
||||||
|
SCK_PIN = GPIO10
|
||||||
|
MI_PIN = GPIO8
|
||||||
|
MO_PIN = GPIO7
|
||||||
|
|
||||||
|
SPI_SCK_PIN = SCK_PIN
|
||||||
|
SPI_SDI_PIN = MI_PIN
|
||||||
|
SPI_SDO_PIN = MO_PIN
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
NEOPIXEL = GPIO2
|
||||||
|
WS2812 = GPIO2
|
||||||
|
|
||||||
|
// also used for boot button.
|
||||||
|
// set it to be an input-with-pullup
|
||||||
|
BUTTON = GPIO9
|
||||||
|
)
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
//go:build thumby
|
||||||
|
|
||||||
|
// This contains the pin mappings for the Thumby.
|
||||||
|
//
|
||||||
|
// https://thumby.us/
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/rp"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
THUMBY_SCK_PIN = I2C1_SDA_PIN
|
||||||
|
THUMBY_SDA_PIN = I2C1_SCL_PIN
|
||||||
|
|
||||||
|
THUMBY_CS_PIN = GPIO16
|
||||||
|
THUMBY_DC_PIN = GPIO17
|
||||||
|
THUMBY_RESET_PIN = GPIO20
|
||||||
|
|
||||||
|
THUMBY_LINK_TX_PIN = UART0_TX_PIN
|
||||||
|
THUMBY_LINK_RX_PIN = UART0_RX_PIN
|
||||||
|
THUMBY_LINK_PU_PIN = GPIO2
|
||||||
|
|
||||||
|
THUMBY_BTN_LDPAD_PIN = GPIO3
|
||||||
|
THUMBY_BTN_RDPAD_PIN = GPIO5
|
||||||
|
THUMBY_BTN_UDPAD_PIN = GPIO4
|
||||||
|
THUMBY_BTN_DDPAD_PIN = GPIO6
|
||||||
|
THUMBY_BTN_B_PIN = GPIO24
|
||||||
|
THUMBY_BTN_A_PIN = GPIO27
|
||||||
|
|
||||||
|
THUMBY_AUDIO_PIN = GPIO28
|
||||||
|
|
||||||
|
THUMBY_SCREEN_RESET_PIN = GPIO20
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C pins
|
||||||
|
const (
|
||||||
|
I2C0_SDA_PIN Pin = NoPin
|
||||||
|
I2C0_SCL_PIN Pin = NoPin
|
||||||
|
|
||||||
|
I2C1_SDA_PIN Pin = GPIO18
|
||||||
|
I2C1_SCL_PIN Pin = GPIO19
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
const (
|
||||||
|
SPI0_SCK_PIN = GPIO18
|
||||||
|
SPI0_SDO_PIN = GPIO19
|
||||||
|
SPI0_SDI_PIN = GPIO16
|
||||||
|
|
||||||
|
SPI1_SCK_PIN = NoPin
|
||||||
|
SPI1_SDO_PIN = NoPin
|
||||||
|
SPI1_SDI_PIN = NoPin
|
||||||
|
)
|
||||||
|
|
||||||
|
// Onboard crystal oscillator frequency, in MHz.
|
||||||
|
const (
|
||||||
|
xoscFreq = 12 // MHz
|
||||||
|
)
|
||||||
|
|
||||||
|
// USB CDC identifiers
|
||||||
|
const (
|
||||||
|
usb_STRING_PRODUCT = "Thumby"
|
||||||
|
usb_STRING_MANUFACTURER = "TinyCircuits"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
usb_VID uint16 = 0x2E8A
|
||||||
|
usb_PID uint16 = 0x0005
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART pins
|
||||||
|
const (
|
||||||
|
UART0_TX_PIN = GPIO0
|
||||||
|
UART0_RX_PIN = GPIO1
|
||||||
|
UART_TX_PIN = UART0_TX_PIN
|
||||||
|
UART_RX_PIN = UART0_RX_PIN
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART on the Thumby
|
||||||
|
var (
|
||||||
|
UART0 = &_UART0
|
||||||
|
_UART0 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: rp.UART0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var DefaultUART = UART0
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||||
|
}
|
||||||
@@ -353,6 +353,9 @@ var (
|
|||||||
|
|
||||||
// RTL8720D (tx: PB24, rx: PC24)
|
// RTL8720D (tx: PB24, rx: PC24)
|
||||||
UART3 = &sercomUSART0
|
UART3 = &sercomUSART0
|
||||||
|
|
||||||
|
// Right-hand grove port (tx: D0, rx: D1)
|
||||||
|
UART4 = &sercomUSART4
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import (
|
|||||||
"runtime/volatile"
|
"runtime/volatile"
|
||||||
)
|
)
|
||||||
|
|
||||||
const bufferSize = 128
|
|
||||||
|
|
||||||
// RingBuffer is ring buffer implementation inspired by post at
|
// RingBuffer is ring buffer implementation inspired by post at
|
||||||
// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
|
// https://www.embeddedrelated.com/showthread/comp.arch.embedded/77084-1.php
|
||||||
type RingBuffer struct {
|
type RingBuffer struct {
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build atmega
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
const bufferSize = 32
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build !atmega
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
const bufferSize = 128
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
//go:build atmega || nrf || sam || stm32 || fe310 || k210 || rp2040 || mimxrt1062
|
//go:build atmega || nrf || sam || stm32 || fe310 || k210 || rp2040 || mimxrt1062 || (esp32c3 && !m5stamp_c3)
|
||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
|
|||||||
@@ -11,10 +11,19 @@ import (
|
|||||||
|
|
||||||
// I2C on AVR.
|
// I2C on AVR.
|
||||||
type I2C struct {
|
type I2C struct {
|
||||||
}
|
srReg *volatile.Register8
|
||||||
|
brReg *volatile.Register8
|
||||||
|
crReg *volatile.Register8
|
||||||
|
drReg *volatile.Register8
|
||||||
|
|
||||||
// I2C0 is the only I2C interface on most AVRs.
|
srPS0 byte
|
||||||
var I2C0 *I2C = nil
|
srPS1 byte
|
||||||
|
crEN byte
|
||||||
|
crINT byte
|
||||||
|
crSTO byte
|
||||||
|
crEA byte
|
||||||
|
crSTA byte
|
||||||
|
}
|
||||||
|
|
||||||
// I2CConfig is used to store config info for I2C.
|
// I2CConfig is used to store config info for I2C.
|
||||||
type I2CConfig struct {
|
type I2CConfig struct {
|
||||||
@@ -37,16 +46,16 @@ func (i2c *I2C) Configure(config I2CConfig) error {
|
|||||||
// SetBaudRate sets the communication speed for I2C.
|
// SetBaudRate sets the communication speed for I2C.
|
||||||
func (i2c *I2C) SetBaudRate(br uint32) error {
|
func (i2c *I2C) SetBaudRate(br uint32) error {
|
||||||
// Initialize twi prescaler and bit rate.
|
// Initialize twi prescaler and bit rate.
|
||||||
avr.TWSR.SetBits((avr.TWSR_TWPS0 | avr.TWSR_TWPS1))
|
i2c.srReg.SetBits((i2c.srPS0 | i2c.srPS1))
|
||||||
|
|
||||||
// twi bit rate formula from atmega128 manual pg. 204:
|
// twi bit rate formula from atmega128 manual pg. 204:
|
||||||
// SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
|
// SCL Frequency = CPU Clock Frequency / (16 + (2 * TWBR))
|
||||||
// NOTE: TWBR should be 10 or higher for controller mode.
|
// NOTE: TWBR should be 10 or higher for controller mode.
|
||||||
// It is 72 for a 16mhz board with 100kHz TWI
|
// It is 72 for a 16mhz board with 100kHz TWI
|
||||||
avr.TWBR.Set(uint8(((CPUFrequency() / br) - 16) / 2))
|
i2c.brReg.Set(uint8(((CPUFrequency() / br) - 16) / 2))
|
||||||
|
|
||||||
// Enable twi module.
|
// Enable twi module.
|
||||||
avr.TWCR.Set(avr.TWCR_TWEN)
|
i2c.crReg.Set(i2c.crEN)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -77,10 +86,10 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
|
|||||||
// start starts an I2C communication session.
|
// start starts an I2C communication session.
|
||||||
func (i2c *I2C) start(address uint8, write bool) {
|
func (i2c *I2C) start(address uint8, write bool) {
|
||||||
// Clear TWI interrupt flag, put start condition on SDA, and enable TWI.
|
// Clear TWI interrupt flag, put start condition on SDA, and enable TWI.
|
||||||
avr.TWCR.Set((avr.TWCR_TWINT | avr.TWCR_TWSTA | avr.TWCR_TWEN))
|
i2c.crReg.Set((i2c.crINT | i2c.crSTA | i2c.crEN))
|
||||||
|
|
||||||
// Wait till start condition is transmitted.
|
// Wait till start condition is transmitted.
|
||||||
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
|
for !i2c.crReg.HasBits(i2c.crINT) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write 7-bit shifted peripheral address.
|
// Write 7-bit shifted peripheral address.
|
||||||
@@ -94,23 +103,23 @@ func (i2c *I2C) start(address uint8, write bool) {
|
|||||||
// stop ends an I2C communication session.
|
// stop ends an I2C communication session.
|
||||||
func (i2c *I2C) stop() {
|
func (i2c *I2C) stop() {
|
||||||
// Send stop condition.
|
// Send stop condition.
|
||||||
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWSTO)
|
i2c.crReg.Set(i2c.crEN | i2c.crINT | i2c.crSTO)
|
||||||
|
|
||||||
// Wait for stop condition to be executed on bus.
|
// Wait for stop condition to be executed on bus.
|
||||||
for !avr.TWCR.HasBits(avr.TWCR_TWSTO) {
|
for !i2c.crReg.HasBits(i2c.crSTO) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeByte writes a single byte to the I2C bus.
|
// writeByte writes a single byte to the I2C bus.
|
||||||
func (i2c *I2C) writeByte(data byte) error {
|
func (i2c *I2C) writeByte(data byte) error {
|
||||||
// Write data to register.
|
// Write data to register.
|
||||||
avr.TWDR.Set(data)
|
i2c.drReg.Set(data)
|
||||||
|
|
||||||
// Clear TWI interrupt flag and enable TWI.
|
// Clear TWI interrupt flag and enable TWI.
|
||||||
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT)
|
i2c.crReg.Set(i2c.crEN | i2c.crINT)
|
||||||
|
|
||||||
// Wait till data is transmitted.
|
// Wait till data is transmitted.
|
||||||
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
|
for !i2c.crReg.HasBits(i2c.crINT) {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -118,13 +127,13 @@ func (i2c *I2C) writeByte(data byte) error {
|
|||||||
// readByte reads a single byte from the I2C bus.
|
// readByte reads a single byte from the I2C bus.
|
||||||
func (i2c *I2C) readByte() byte {
|
func (i2c *I2C) readByte() byte {
|
||||||
// Clear TWI interrupt flag and enable TWI.
|
// Clear TWI interrupt flag and enable TWI.
|
||||||
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWEA)
|
i2c.crReg.Set(i2c.crEN | i2c.crINT | i2c.crEA)
|
||||||
|
|
||||||
// Wait till read request is transmitted.
|
// Wait till read request is transmitted.
|
||||||
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
|
for !i2c.crReg.HasBits(i2c.crINT) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return byte(avr.TWDR.Get())
|
return byte(i2c.drReg.Get())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always use UART0 as the serial output.
|
// Always use UART0 as the serial output.
|
||||||
@@ -170,10 +179,18 @@ func (uart *UART) Configure(config UARTConfig) {
|
|||||||
config.BaudRate = 9600
|
config.BaudRate = 9600
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set baud rate based on prescale formula from
|
// Prescale formula for u2x mode from AVR MiniCore source code.
|
||||||
// https://www.microchip.com/webdoc/AVRLibcReferenceManual/FAQ_1faq_wrong_baud_rate.html
|
// Same as formula from specification but taking into account rounding error.
|
||||||
// ((F_CPU + UART_BAUD_RATE * 8L) / (UART_BAUD_RATE * 16L) - 1)
|
ps := (CPUFrequency()/4/config.BaudRate - 1) / 2
|
||||||
ps := ((CPUFrequency()+config.BaudRate*8)/(config.BaudRate*16) - 1)
|
uart.statusRegA.SetBits(avr.UCSR0A_U2X0)
|
||||||
|
|
||||||
|
// Hardcoded exception for 57600 for compatibility with older bootloaders.
|
||||||
|
// Also, prescale cannot be > 4095, so switch back to non-u2x mode if the baud rate is too low.
|
||||||
|
if (CPUFrequency() == 16000000 && config.BaudRate == 57600) || ps > 0xfff {
|
||||||
|
ps = (CPUFrequency()/8/config.BaudRate - 1) / 2
|
||||||
|
uart.statusRegA.ClearBits(avr.UCSR0A_U2X0)
|
||||||
|
}
|
||||||
|
|
||||||
uart.baudRegH.Set(uint8(ps >> 8))
|
uart.baudRegH.Set(uint8(ps >> 8))
|
||||||
uart.baudRegL.Set(uint8(ps & 0xff))
|
uart.baudRegL.Set(uint8(ps & 0xff))
|
||||||
|
|
||||||
@@ -221,6 +238,17 @@ type SPI struct {
|
|||||||
spdr *volatile.Register8
|
spdr *volatile.Register8
|
||||||
spsr *volatile.Register8
|
spsr *volatile.Register8
|
||||||
|
|
||||||
|
spcrR0 byte
|
||||||
|
spcrR1 byte
|
||||||
|
spcrCPHA byte
|
||||||
|
spcrCPOL byte
|
||||||
|
spcrDORD byte
|
||||||
|
spcrSPE byte
|
||||||
|
spcrMSTR byte
|
||||||
|
|
||||||
|
spsrI2X byte
|
||||||
|
spsrSPIF byte
|
||||||
|
|
||||||
// The io pins for the SPIx port set by the chip
|
// The io pins for the SPIx port set by the chip
|
||||||
sck Pin
|
sck Pin
|
||||||
sdi Pin
|
sdi Pin
|
||||||
@@ -264,39 +292,39 @@ func (s SPI) Configure(config SPIConfig) error {
|
|||||||
|
|
||||||
switch {
|
switch {
|
||||||
case frequencyDivider >= 128:
|
case frequencyDivider >= 128:
|
||||||
s.spcr.SetBits(avr.SPCR_SPR0 | avr.SPCR_SPR1)
|
s.spcr.SetBits(s.spcrR0 | s.spcrR1)
|
||||||
case frequencyDivider >= 64:
|
case frequencyDivider >= 64:
|
||||||
s.spcr.SetBits(avr.SPCR_SPR1)
|
s.spcr.SetBits(s.spcrR1)
|
||||||
case frequencyDivider >= 32:
|
case frequencyDivider >= 32:
|
||||||
s.spcr.SetBits(avr.SPCR_SPR1)
|
s.spcr.SetBits(s.spcrR1)
|
||||||
s.spsr.SetBits(avr.SPSR_SPI2X)
|
s.spsr.SetBits(s.spsrI2X)
|
||||||
case frequencyDivider >= 16:
|
case frequencyDivider >= 16:
|
||||||
s.spcr.SetBits(avr.SPCR_SPR0)
|
s.spcr.SetBits(s.spcrR0)
|
||||||
case frequencyDivider >= 8:
|
case frequencyDivider >= 8:
|
||||||
s.spcr.SetBits(avr.SPCR_SPR0)
|
s.spcr.SetBits(s.spcrR0)
|
||||||
s.spsr.SetBits(avr.SPSR_SPI2X)
|
s.spsr.SetBits(s.spsrI2X)
|
||||||
case frequencyDivider >= 4:
|
case frequencyDivider >= 4:
|
||||||
// The clock is already set to all 0's.
|
// The clock is already set to all 0's.
|
||||||
default: // defaults to fastest which is /2
|
default: // defaults to fastest which is /2
|
||||||
s.spsr.SetBits(avr.SPSR_SPI2X)
|
s.spsr.SetBits(s.spsrI2X)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch config.Mode {
|
switch config.Mode {
|
||||||
case Mode1:
|
case Mode1:
|
||||||
s.spcr.SetBits(avr.SPCR_CPHA)
|
s.spcr.SetBits(s.spcrCPHA)
|
||||||
case Mode2:
|
case Mode2:
|
||||||
s.spcr.SetBits(avr.SPCR_CPOL)
|
s.spcr.SetBits(s.spcrCPHA)
|
||||||
case Mode3:
|
case Mode3:
|
||||||
s.spcr.SetBits(avr.SPCR_CPHA | avr.SPCR_CPOL)
|
s.spcr.SetBits(s.spcrCPHA | s.spcrCPOL)
|
||||||
default: // default is mode 0
|
default: // default is mode 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.LSBFirst {
|
if config.LSBFirst {
|
||||||
s.spcr.SetBits(avr.SPCR_DORD)
|
s.spcr.SetBits(s.spcrDORD)
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable SPI, set controller, set clock rate
|
// enable SPI, set controller, set clock rate
|
||||||
s.spcr.SetBits(avr.SPCR_SPE | avr.SPCR_MSTR)
|
s.spcr.SetBits(s.spcrSPE | s.spcrMSTR)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -305,7 +333,7 @@ func (s SPI) Configure(config SPIConfig) error {
|
|||||||
func (s SPI) Transfer(b byte) (byte, error) {
|
func (s SPI) Transfer(b byte) (byte, error) {
|
||||||
s.spdr.Set(uint8(b))
|
s.spdr.Set(uint8(b))
|
||||||
|
|
||||||
for !s.spsr.HasBits(avr.SPSR_SPIF) {
|
for !s.spsr.HasBits(s.spsrSPIF) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return byte(s.spdr.Get()), nil
|
return byte(s.spdr.Get()), nil
|
||||||
|
|||||||
@@ -0,0 +1,548 @@
|
|||||||
|
//go:build avr && (atmega328p || atmega328pb)
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/avr"
|
||||||
|
"runtime/interrupt"
|
||||||
|
"runtime/volatile"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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 PD5 and PD6
|
||||||
|
Timer1 = PWM{1} // 16 bit timer for PB1 and PB2
|
||||||
|
Timer2 = PWM{2} // 8 bit timer for PB3 and PD3
|
||||||
|
)
|
||||||
|
|
||||||
|
// Configure enables and configures this PWM.
|
||||||
|
//
|
||||||
|
// For the two 8 bit timers, 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 16MHz, this would be a period of 16µs,
|
||||||
|
// 128µs, 1024µs, 4096µs, or 16384µs.
|
||||||
|
func (pwm PWM) Configure(config PWMConfig) error {
|
||||||
|
switch pwm.num {
|
||||||
|
case 0, 2: // 8-bit timers (Timer/counter 0 and Timer/counter 2)
|
||||||
|
// Calculate the timer prescaler.
|
||||||
|
// While we could configure a flexible top, that would sacrifice one of
|
||||||
|
// the PWM output compare registers and thus a PWM channel. I've chosen
|
||||||
|
// to instead limit this timer to a fixed number of frequencies.
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if pwm.num == 0 {
|
||||||
|
avr.TCCR0B.Set(prescaler)
|
||||||
|
// Set the PWM mode to fast PWM (mode = 3).
|
||||||
|
avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01)
|
||||||
|
// monotonic timer is using the same time as PWM:0
|
||||||
|
// we must adust internal settings of monotonic timer when PWM:0 settings changed
|
||||||
|
adjustMonotonicTimer()
|
||||||
|
} else {
|
||||||
|
avr.TCCR2B.Set(prescaler)
|
||||||
|
// Set the PWM mode to fast PWM (mode = 3).
|
||||||
|
avr.TCCR2A.Set(avr.TCCR2A_WGM20 | avr.TCCR2A_WGM21)
|
||||||
|
}
|
||||||
|
case 1: // Timer/counter 1
|
||||||
|
// The top value is the number of PWM ticks a PWM period takes. It is
|
||||||
|
// initially picked assuming an unlimited counter top and no PWM
|
||||||
|
// prescaler.
|
||||||
|
var top uint64
|
||||||
|
if config.Period == 0 {
|
||||||
|
// Use a top appropriate for LEDs. Picking a relatively low period
|
||||||
|
// here (0xff) for consistency with the other timers.
|
||||||
|
top = 0xff
|
||||||
|
} else {
|
||||||
|
// The formula below calculates the following formula, optimized:
|
||||||
|
// top = period * (CPUFrequency() / 1e9)
|
||||||
|
// By dividing the CPU frequency first (an operation that is easily
|
||||||
|
// optimized away) the period has less chance of overflowing.
|
||||||
|
top = config.Period * (uint64(CPUFrequency()) / 1000000) / 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
avr.TCCR1A.Set(avr.TCCR1A_WGM11)
|
||||||
|
|
||||||
|
// The ideal PWM period may be larger than would fit in the PWM counter,
|
||||||
|
// which is 16 bits (see maxTop). Therefore, try to make the PWM clock
|
||||||
|
// speed lower with a prescaler to make the top value fit the maximum
|
||||||
|
// top value.
|
||||||
|
const maxTop = 0x10000
|
||||||
|
switch {
|
||||||
|
case top <= maxTop:
|
||||||
|
avr.TCCR1B.Set(3<<3 | 1) // no prescaling
|
||||||
|
case top/8 <= maxTop:
|
||||||
|
avr.TCCR1B.Set(3<<3 | 2) // divide by 8
|
||||||
|
top /= 8
|
||||||
|
case top/64 <= maxTop:
|
||||||
|
avr.TCCR1B.Set(3<<3 | 3) // divide by 64
|
||||||
|
top /= 64
|
||||||
|
case top/256 <= maxTop:
|
||||||
|
avr.TCCR1B.Set(3<<3 | 4) // divide by 256
|
||||||
|
top /= 256
|
||||||
|
case top/1024 <= maxTop:
|
||||||
|
avr.TCCR1B.Set(3<<3 | 5) // divide by 1024
|
||||||
|
top /= 1024
|
||||||
|
default:
|
||||||
|
return ErrPWMPeriodTooLong
|
||||||
|
}
|
||||||
|
|
||||||
|
// A top of 0x10000 is at 100% duty cycle. Subtract one because the
|
||||||
|
// counter counts from 0, not 1 (avoiding an off-by-one).
|
||||||
|
top -= 1
|
||||||
|
|
||||||
|
avr.ICR1H.Set(uint8(top >> 8))
|
||||||
|
avr.ICR1L.Set(uint8(top))
|
||||||
|
}
|
||||||
|
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 != 1 {
|
||||||
|
return ErrPWMPeriodTooLong // TODO better error message
|
||||||
|
}
|
||||||
|
|
||||||
|
// The top value is the number of PWM ticks a PWM period takes. It is
|
||||||
|
// initially picked assuming an unlimited counter top and no PWM
|
||||||
|
// prescaler.
|
||||||
|
var top uint64
|
||||||
|
if period == 0 {
|
||||||
|
// Use a top appropriate for LEDs. Picking a relatively low period
|
||||||
|
// here (0xff) for consistency with the other timers.
|
||||||
|
top = 0xff
|
||||||
|
} else {
|
||||||
|
// The formula below calculates the following formula, optimized:
|
||||||
|
// top = period * (CPUFrequency() / 1e9)
|
||||||
|
// By dividing the CPU frequency first (an operation that is easily
|
||||||
|
// optimized away) the period has less chance of overflowing.
|
||||||
|
top = period * (uint64(CPUFrequency()) / 1000000) / 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
prescaler := avr.TCCR1B.Get() & 0x7
|
||||||
|
switch prescaler {
|
||||||
|
case 1:
|
||||||
|
top /= 1
|
||||||
|
case 2:
|
||||||
|
top /= 8
|
||||||
|
case 3:
|
||||||
|
top /= 64
|
||||||
|
case 4:
|
||||||
|
top /= 256
|
||||||
|
case 5:
|
||||||
|
top /= 1024
|
||||||
|
}
|
||||||
|
|
||||||
|
// A top of 0x10000 is at 100% duty cycle. Subtract one because the counter
|
||||||
|
// counts from 0, not 1 (avoiding an off-by-one).
|
||||||
|
top -= 1
|
||||||
|
|
||||||
|
if top > 0xffff {
|
||||||
|
return ErrPWMPeriodTooLong
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning: this change is not atomic!
|
||||||
|
avr.ICR1H.Set(uint8(top >> 8))
|
||||||
|
avr.ICR1L.Set(uint8(top))
|
||||||
|
|
||||||
|
// ... and because of that, set the counter back to zero to avoid most of
|
||||||
|
// the effects of this non-atomicity.
|
||||||
|
avr.TCNT1H.Set(0)
|
||||||
|
avr.TCNT1L.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 {
|
||||||
|
// Timer 1 has a configurable top value.
|
||||||
|
low := avr.ICR1L.Get()
|
||||||
|
high := avr.ICR1H.Get()
|
||||||
|
return uint32(high)<<8 | uint32(low) + 1
|
||||||
|
}
|
||||||
|
// Other timers go from 0 to 0xff (0x100 or 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:
|
||||||
|
mask := interrupt.Disable()
|
||||||
|
low := avr.TCNT1L.Get()
|
||||||
|
high := avr.TCNT1H.Get()
|
||||||
|
interrupt.Restore(mask)
|
||||||
|
return uint32(high)<<8 | uint32(low)
|
||||||
|
case 2:
|
||||||
|
return uint32(avr.TCNT2.Get())
|
||||||
|
}
|
||||||
|
// Unknown PWM.
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 uint8
|
||||||
|
switch pwm.num {
|
||||||
|
case 0:
|
||||||
|
prescaler = avr.TCCR0B.Get() & 0x7
|
||||||
|
case 1:
|
||||||
|
prescaler = avr.TCCR1B.Get() & 0x7
|
||||||
|
case 2:
|
||||||
|
prescaler = avr.TCCR2B.Get() & 0x7
|
||||||
|
}
|
||||||
|
top := uint64(pwm.Top())
|
||||||
|
switch prescaler {
|
||||||
|
case 1: // prescaler 1
|
||||||
|
return 1 * top * 1000 / uint64(CPUFrequency()/1e6)
|
||||||
|
case 2: // prescaler 8
|
||||||
|
return 8 * top * 1000 / uint64(CPUFrequency()/1e6)
|
||||||
|
case 3: // prescaler 64
|
||||||
|
return 64 * top * 1000 / uint64(CPUFrequency()/1e6)
|
||||||
|
case 4: // prescaler 256
|
||||||
|
return 256 * top * 1000 / uint64(CPUFrequency()/1e6)
|
||||||
|
case 5: // prescaler 1024
|
||||||
|
return 1024 * top * 1000 / uint64(CPUFrequency()/1e6)
|
||||||
|
default: // unknown clock source
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 PD6: // channel A
|
||||||
|
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1)
|
||||||
|
return 0, nil
|
||||||
|
case PD5: // channel B
|
||||||
|
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
switch pin {
|
||||||
|
case PB1: // channel A
|
||||||
|
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1)
|
||||||
|
return 0, nil
|
||||||
|
case PB2: // channel B
|
||||||
|
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1)
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
switch pin {
|
||||||
|
case PB3: // channel A
|
||||||
|
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
|
||||||
|
return 0, nil
|
||||||
|
case PD3: // channel B
|
||||||
|
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1)
|
||||||
|
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%.
|
||||||
|
//
|
||||||
|
// Note: the invert state may not be applied on the AVR until the next call to
|
||||||
|
// ch.Set().
|
||||||
|
func (pwm PWM) SetInverting(channel uint8, inverting bool) {
|
||||||
|
switch pwm.num {
|
||||||
|
case 0:
|
||||||
|
switch channel {
|
||||||
|
case 0: // channel A
|
||||||
|
if inverting {
|
||||||
|
avr.PORTB.SetBits(1 << 6) // PB6 high
|
||||||
|
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A0)
|
||||||
|
} else {
|
||||||
|
avr.PORTB.ClearBits(1 << 6) // PB6 low
|
||||||
|
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A0)
|
||||||
|
}
|
||||||
|
case 1: // channel B
|
||||||
|
if inverting {
|
||||||
|
avr.PORTB.SetBits(1 << 5) // PB5 high
|
||||||
|
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B0)
|
||||||
|
} else {
|
||||||
|
avr.PORTB.ClearBits(1 << 5) // PB5 low
|
||||||
|
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
// Note: the COM1A0/COM1B0 bit is not set with the configuration below.
|
||||||
|
// It will be set the following call to Set(), however.
|
||||||
|
switch channel {
|
||||||
|
case 0: // channel A, PB1
|
||||||
|
if inverting {
|
||||||
|
avr.PORTB.SetBits(1 << 1) // PB1 high
|
||||||
|
} else {
|
||||||
|
avr.PORTB.ClearBits(1 << 1) // PB1 low
|
||||||
|
}
|
||||||
|
case 1: // channel B, PB2
|
||||||
|
if inverting {
|
||||||
|
avr.PORTB.SetBits(1 << 2) // PB2 high
|
||||||
|
} else {
|
||||||
|
avr.PORTB.ClearBits(1 << 2) // PB2 low
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 2:
|
||||||
|
switch channel {
|
||||||
|
case 0: // channel A
|
||||||
|
if inverting {
|
||||||
|
avr.PORTB.SetBits(1 << 3) // PB3 high
|
||||||
|
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A0)
|
||||||
|
} else {
|
||||||
|
avr.PORTB.ClearBits(1 << 3) // PB3 low
|
||||||
|
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A0)
|
||||||
|
}
|
||||||
|
case 1: // channel B
|
||||||
|
if inverting {
|
||||||
|
avr.PORTD.SetBits(1 << 3) // PD3 high
|
||||||
|
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B0)
|
||||||
|
} else {
|
||||||
|
avr.PORTD.ClearBits(1 << 3) // PD3 low
|
||||||
|
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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:
|
||||||
|
value := uint16(value)
|
||||||
|
switch channel {
|
||||||
|
case 0: // channel A
|
||||||
|
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
|
||||||
|
if value == 0 {
|
||||||
|
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B1)
|
||||||
|
} else {
|
||||||
|
avr.OCR0B.Set(uint8(value) - 1)
|
||||||
|
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// monotonic timer is using the same time as PWM:0
|
||||||
|
// we must adust internal settings of monotonic timer when PWM:0 settings changed
|
||||||
|
adjustMonotonicTimer()
|
||||||
|
case 1:
|
||||||
|
mask := interrupt.Disable()
|
||||||
|
switch channel {
|
||||||
|
case 0: // channel A, PB1
|
||||||
|
if value == 0 {
|
||||||
|
avr.TCCR1A.ClearBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0)
|
||||||
|
} else {
|
||||||
|
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
|
||||||
|
avr.OCR1AH.Set(uint8(value >> 8))
|
||||||
|
avr.OCR1AL.Set(uint8(value))
|
||||||
|
if avr.PORTB.HasBits(1 << 1) { // is PB1 high?
|
||||||
|
// Yes, set the inverting bit.
|
||||||
|
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0)
|
||||||
|
} else {
|
||||||
|
// No, output is non-inverting.
|
||||||
|
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 1: // channel B, PB2
|
||||||
|
if value == 0 {
|
||||||
|
avr.TCCR1A.ClearBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0)
|
||||||
|
} else {
|
||||||
|
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
|
||||||
|
avr.OCR1BH.Set(uint8(value >> 8))
|
||||||
|
avr.OCR1BL.Set(uint8(value))
|
||||||
|
if avr.PORTB.HasBits(1 << 2) { // is PB2 high?
|
||||||
|
// Yes, set the inverting bit.
|
||||||
|
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0)
|
||||||
|
} else {
|
||||||
|
// No, output is non-inverting.
|
||||||
|
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interrupt.Restore(mask)
|
||||||
|
case 2:
|
||||||
|
value := uint16(value)
|
||||||
|
switch channel {
|
||||||
|
case 0: // channel A
|
||||||
|
if value == 0 {
|
||||||
|
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A1)
|
||||||
|
} else {
|
||||||
|
avr.OCR2A.Set(uint8(value - 1))
|
||||||
|
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
|
||||||
|
}
|
||||||
|
case 1: // channel B
|
||||||
|
if value == 0 {
|
||||||
|
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B1)
|
||||||
|
} else {
|
||||||
|
avr.OCR2B.Set(uint8(value - 1))
|
||||||
|
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pin Change Interrupts
|
||||||
|
type PinChange uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
PinRising PinChange = 1 << iota
|
||||||
|
PinFalling
|
||||||
|
PinToggle = PinRising | PinFalling
|
||||||
|
)
|
||||||
|
|
||||||
|
func (pin Pin) SetInterrupt(pinChange PinChange, callback func(Pin)) (err error) {
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case pin >= PB0 && pin <= PB7:
|
||||||
|
// PCMSK0 - PCINT0-7
|
||||||
|
pinStates[0] = avr.PINB.Get()
|
||||||
|
pinIndex := pin - PB0
|
||||||
|
if pinChange&PinRising > 0 {
|
||||||
|
pinCallbacks[0][pinIndex][0] = callback
|
||||||
|
}
|
||||||
|
if pinChange&PinFalling > 0 {
|
||||||
|
pinCallbacks[0][pinIndex][1] = callback
|
||||||
|
}
|
||||||
|
if callback != nil {
|
||||||
|
avr.PCMSK0.SetBits(1 << pinIndex)
|
||||||
|
} else {
|
||||||
|
avr.PCMSK0.ClearBits(1 << pinIndex)
|
||||||
|
}
|
||||||
|
avr.PCICR.SetBits(avr.PCICR_PCIE0)
|
||||||
|
interrupt.New(avr.IRQ_PCINT0, handlePCINT0Interrupts)
|
||||||
|
case pin >= PC0 && pin <= PC7:
|
||||||
|
// PCMSK1 - PCINT8-14
|
||||||
|
pinStates[1] = avr.PINC.Get()
|
||||||
|
pinIndex := pin - PC0
|
||||||
|
if pinChange&PinRising > 0 {
|
||||||
|
pinCallbacks[1][pinIndex][0] = callback
|
||||||
|
}
|
||||||
|
if pinChange&PinFalling > 0 {
|
||||||
|
pinCallbacks[1][pinIndex][1] = callback
|
||||||
|
}
|
||||||
|
if callback != nil {
|
||||||
|
avr.PCMSK1.SetBits(1 << pinIndex)
|
||||||
|
} else {
|
||||||
|
avr.PCMSK1.ClearBits(1 << pinIndex)
|
||||||
|
}
|
||||||
|
avr.PCICR.SetBits(avr.PCICR_PCIE1)
|
||||||
|
interrupt.New(avr.IRQ_PCINT1, handlePCINT1Interrupts)
|
||||||
|
case pin >= PD0 && pin <= PD7:
|
||||||
|
// PCMSK2 - PCINT16-23
|
||||||
|
pinStates[2] = avr.PIND.Get()
|
||||||
|
pinIndex := pin - PD0
|
||||||
|
if pinChange&PinRising > 0 {
|
||||||
|
pinCallbacks[2][pinIndex][0] = callback
|
||||||
|
}
|
||||||
|
if pinChange&PinFalling > 0 {
|
||||||
|
pinCallbacks[2][pinIndex][1] = callback
|
||||||
|
}
|
||||||
|
if callback != nil {
|
||||||
|
avr.PCMSK2.SetBits(1 << pinIndex)
|
||||||
|
} else {
|
||||||
|
avr.PCMSK2.ClearBits(1 << pinIndex)
|
||||||
|
}
|
||||||
|
avr.PCICR.SetBits(avr.PCICR_PCIE2)
|
||||||
|
interrupt.New(avr.IRQ_PCINT2, handlePCINT2Interrupts)
|
||||||
|
default:
|
||||||
|
return ErrInvalidInputPin
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var pinCallbacks [3][8][2]func(Pin)
|
||||||
|
var pinStates [3]uint8
|
||||||
|
|
||||||
|
func handlePCINTInterrupts(intr uint8, port *volatile.Register8) {
|
||||||
|
current := port.Get()
|
||||||
|
change := pinStates[intr] ^ current
|
||||||
|
pinStates[intr] = current
|
||||||
|
for i := uint8(0); i < 8; i++ {
|
||||||
|
if (change>>i)&0x01 != 0x01 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
pin := Pin(intr*8 + i)
|
||||||
|
value := pin.Get()
|
||||||
|
if value && pinCallbacks[intr][i][0] != nil {
|
||||||
|
pinCallbacks[intr][i][0](pin)
|
||||||
|
}
|
||||||
|
if !value && pinCallbacks[intr][i][1] != nil {
|
||||||
|
pinCallbacks[intr][i][1](pin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePCINT0Interrupts(intr interrupt.Interrupt) {
|
||||||
|
handlePCINTInterrupts(0, avr.PINB)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePCINT1Interrupts(intr interrupt.Interrupt) {
|
||||||
|
handlePCINTInterrupts(1, avr.PINC)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlePCINT2Interrupts(intr interrupt.Interrupt) {
|
||||||
|
handlePCINTInterrupts(2, avr.PIND)
|
||||||
|
}
|
||||||
@@ -4,12 +4,49 @@ package machine
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"device/avr"
|
"device/avr"
|
||||||
"runtime/interrupt"
|
|
||||||
"runtime/volatile"
|
"runtime/volatile"
|
||||||
)
|
)
|
||||||
|
|
||||||
const irq_USART0_RX = avr.IRQ_USART_RX
|
const irq_USART0_RX = avr.IRQ_USART_RX
|
||||||
|
|
||||||
|
// I2C0 is the only I2C interface on most AVRs.
|
||||||
|
var I2C0 = &I2C{
|
||||||
|
srReg: avr.TWSR,
|
||||||
|
brReg: avr.TWBR,
|
||||||
|
crReg: avr.TWCR,
|
||||||
|
drReg: avr.TWDR,
|
||||||
|
srPS0: avr.TWSR_TWPS0,
|
||||||
|
srPS1: avr.TWSR_TWPS1,
|
||||||
|
crEN: avr.TWCR_TWEN,
|
||||||
|
crINT: avr.TWCR_TWINT,
|
||||||
|
crSTO: avr.TWCR_TWSTO,
|
||||||
|
crEA: avr.TWCR_TWEA,
|
||||||
|
crSTA: avr.TWCR_TWSTA,
|
||||||
|
}
|
||||||
|
|
||||||
|
// SPI configuration
|
||||||
|
var SPI0 = SPI{
|
||||||
|
spcr: avr.SPCR,
|
||||||
|
spdr: avr.SPDR,
|
||||||
|
spsr: avr.SPSR,
|
||||||
|
|
||||||
|
spcrR0: avr.SPCR_SPR0,
|
||||||
|
spcrR1: avr.SPCR_SPR1,
|
||||||
|
spcrCPHA: avr.SPCR_CPHA,
|
||||||
|
spcrCPOL: avr.SPCR_CPOL,
|
||||||
|
spcrDORD: avr.SPCR_DORD,
|
||||||
|
spcrSPE: avr.SPCR_SPE,
|
||||||
|
spcrMSTR: avr.SPCR_MSTR,
|
||||||
|
|
||||||
|
spsrI2X: avr.SPSR_SPI2X,
|
||||||
|
spsrSPIF: avr.SPSR_SPIF,
|
||||||
|
|
||||||
|
sck: PB5,
|
||||||
|
sdo: PB3,
|
||||||
|
sdi: PB4,
|
||||||
|
cs: PB2,
|
||||||
|
}
|
||||||
|
|
||||||
// getPortMask returns the PORTx register and mask for the pin.
|
// getPortMask returns the PORTx register and mask for the pin.
|
||||||
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
||||||
switch {
|
switch {
|
||||||
@@ -21,552 +58,3 @@ func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
|||||||
return avr.PORTD, 1 << uint8(p-portD)
|
return avr.PORTD, 1 << uint8(p-portD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 PD5 and PD6
|
|
||||||
Timer1 = PWM{1} // 16 bit timer for PB1 and PB2
|
|
||||||
Timer2 = PWM{2} // 8 bit timer for PB3 and PD3
|
|
||||||
)
|
|
||||||
|
|
||||||
// Configure enables and configures this PWM.
|
|
||||||
//
|
|
||||||
// For the two 8 bit timers, 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 16MHz, this would be a period of 16µs,
|
|
||||||
// 128µs, 1024µs, 4096µs, or 16384µs.
|
|
||||||
func (pwm PWM) Configure(config PWMConfig) error {
|
|
||||||
switch pwm.num {
|
|
||||||
case 0, 2: // 8-bit timers (Timer/counter 0 and Timer/counter 2)
|
|
||||||
// Calculate the timer prescaler.
|
|
||||||
// While we could configure a flexible top, that would sacrifice one of
|
|
||||||
// the PWM output compare registers and thus a PWM channel. I've chosen
|
|
||||||
// to instead limit this timer to a fixed number of frequencies.
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
if pwm.num == 0 {
|
|
||||||
avr.TCCR0B.Set(prescaler)
|
|
||||||
// Set the PWM mode to fast PWM (mode = 3).
|
|
||||||
avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01)
|
|
||||||
// monotonic timer is using the same time as PWM:0
|
|
||||||
// we must adust internal settings of monotonic timer when PWM:0 settings changed
|
|
||||||
adjustMonotonicTimer()
|
|
||||||
} else {
|
|
||||||
avr.TCCR2B.Set(prescaler)
|
|
||||||
// Set the PWM mode to fast PWM (mode = 3).
|
|
||||||
avr.TCCR2A.Set(avr.TCCR2A_WGM20 | avr.TCCR2A_WGM21)
|
|
||||||
}
|
|
||||||
case 1: // Timer/counter 1
|
|
||||||
// The top value is the number of PWM ticks a PWM period takes. It is
|
|
||||||
// initially picked assuming an unlimited counter top and no PWM
|
|
||||||
// prescaler.
|
|
||||||
var top uint64
|
|
||||||
if config.Period == 0 {
|
|
||||||
// Use a top appropriate for LEDs. Picking a relatively low period
|
|
||||||
// here (0xff) for consistency with the other timers.
|
|
||||||
top = 0xff
|
|
||||||
} else {
|
|
||||||
// The formula below calculates the following formula, optimized:
|
|
||||||
// top = period * (CPUFrequency() / 1e9)
|
|
||||||
// By dividing the CPU frequency first (an operation that is easily
|
|
||||||
// optimized away) the period has less chance of overflowing.
|
|
||||||
top = config.Period * (uint64(CPUFrequency()) / 1000000) / 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
avr.TCCR1A.Set(avr.TCCR1A_WGM11)
|
|
||||||
|
|
||||||
// The ideal PWM period may be larger than would fit in the PWM counter,
|
|
||||||
// which is 16 bits (see maxTop). Therefore, try to make the PWM clock
|
|
||||||
// speed lower with a prescaler to make the top value fit the maximum
|
|
||||||
// top value.
|
|
||||||
const maxTop = 0x10000
|
|
||||||
switch {
|
|
||||||
case top <= maxTop:
|
|
||||||
avr.TCCR1B.Set(3<<3 | 1) // no prescaling
|
|
||||||
case top/8 <= maxTop:
|
|
||||||
avr.TCCR1B.Set(3<<3 | 2) // divide by 8
|
|
||||||
top /= 8
|
|
||||||
case top/64 <= maxTop:
|
|
||||||
avr.TCCR1B.Set(3<<3 | 3) // divide by 64
|
|
||||||
top /= 64
|
|
||||||
case top/256 <= maxTop:
|
|
||||||
avr.TCCR1B.Set(3<<3 | 4) // divide by 256
|
|
||||||
top /= 256
|
|
||||||
case top/1024 <= maxTop:
|
|
||||||
avr.TCCR1B.Set(3<<3 | 5) // divide by 1024
|
|
||||||
top /= 1024
|
|
||||||
default:
|
|
||||||
return ErrPWMPeriodTooLong
|
|
||||||
}
|
|
||||||
|
|
||||||
// A top of 0x10000 is at 100% duty cycle. Subtract one because the
|
|
||||||
// counter counts from 0, not 1 (avoiding an off-by-one).
|
|
||||||
top -= 1
|
|
||||||
|
|
||||||
avr.ICR1H.Set(uint8(top >> 8))
|
|
||||||
avr.ICR1L.Set(uint8(top))
|
|
||||||
}
|
|
||||||
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 != 1 {
|
|
||||||
return ErrPWMPeriodTooLong // TODO better error message
|
|
||||||
}
|
|
||||||
|
|
||||||
// The top value is the number of PWM ticks a PWM period takes. It is
|
|
||||||
// initially picked assuming an unlimited counter top and no PWM
|
|
||||||
// prescaler.
|
|
||||||
var top uint64
|
|
||||||
if period == 0 {
|
|
||||||
// Use a top appropriate for LEDs. Picking a relatively low period
|
|
||||||
// here (0xff) for consistency with the other timers.
|
|
||||||
top = 0xff
|
|
||||||
} else {
|
|
||||||
// The formula below calculates the following formula, optimized:
|
|
||||||
// top = period * (CPUFrequency() / 1e9)
|
|
||||||
// By dividing the CPU frequency first (an operation that is easily
|
|
||||||
// optimized away) the period has less chance of overflowing.
|
|
||||||
top = period * (uint64(CPUFrequency()) / 1000000) / 1000
|
|
||||||
}
|
|
||||||
|
|
||||||
prescaler := avr.TCCR1B.Get() & 0x7
|
|
||||||
switch prescaler {
|
|
||||||
case 1:
|
|
||||||
top /= 1
|
|
||||||
case 2:
|
|
||||||
top /= 8
|
|
||||||
case 3:
|
|
||||||
top /= 64
|
|
||||||
case 4:
|
|
||||||
top /= 256
|
|
||||||
case 5:
|
|
||||||
top /= 1024
|
|
||||||
}
|
|
||||||
|
|
||||||
// A top of 0x10000 is at 100% duty cycle. Subtract one because the counter
|
|
||||||
// counts from 0, not 1 (avoiding an off-by-one).
|
|
||||||
top -= 1
|
|
||||||
|
|
||||||
if top > 0xffff {
|
|
||||||
return ErrPWMPeriodTooLong
|
|
||||||
}
|
|
||||||
|
|
||||||
// Warning: this change is not atomic!
|
|
||||||
avr.ICR1H.Set(uint8(top >> 8))
|
|
||||||
avr.ICR1L.Set(uint8(top))
|
|
||||||
|
|
||||||
// ... and because of that, set the counter back to zero to avoid most of
|
|
||||||
// the effects of this non-atomicity.
|
|
||||||
avr.TCNT1H.Set(0)
|
|
||||||
avr.TCNT1L.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 {
|
|
||||||
// Timer 1 has a configurable top value.
|
|
||||||
low := avr.ICR1L.Get()
|
|
||||||
high := avr.ICR1H.Get()
|
|
||||||
return uint32(high)<<8 | uint32(low) + 1
|
|
||||||
}
|
|
||||||
// Other timers go from 0 to 0xff (0x100 or 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:
|
|
||||||
mask := interrupt.Disable()
|
|
||||||
low := avr.TCNT1L.Get()
|
|
||||||
high := avr.TCNT1H.Get()
|
|
||||||
interrupt.Restore(mask)
|
|
||||||
return uint32(high)<<8 | uint32(low)
|
|
||||||
case 2:
|
|
||||||
return uint32(avr.TCNT2.Get())
|
|
||||||
}
|
|
||||||
// Unknown PWM.
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 uint8
|
|
||||||
switch pwm.num {
|
|
||||||
case 0:
|
|
||||||
prescaler = avr.TCCR0B.Get() & 0x7
|
|
||||||
case 1:
|
|
||||||
prescaler = avr.TCCR1B.Get() & 0x7
|
|
||||||
case 2:
|
|
||||||
prescaler = avr.TCCR2B.Get() & 0x7
|
|
||||||
}
|
|
||||||
top := uint64(pwm.Top())
|
|
||||||
switch prescaler {
|
|
||||||
case 1: // prescaler 1
|
|
||||||
return 1 * top * 1000 / uint64(CPUFrequency()/1e6)
|
|
||||||
case 2: // prescaler 8
|
|
||||||
return 8 * top * 1000 / uint64(CPUFrequency()/1e6)
|
|
||||||
case 3: // prescaler 64
|
|
||||||
return 64 * top * 1000 / uint64(CPUFrequency()/1e6)
|
|
||||||
case 4: // prescaler 256
|
|
||||||
return 256 * top * 1000 / uint64(CPUFrequency()/1e6)
|
|
||||||
case 5: // prescaler 1024
|
|
||||||
return 1024 * top * 1000 / uint64(CPUFrequency()/1e6)
|
|
||||||
default: // unknown clock source
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 PD6: // channel A
|
|
||||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1)
|
|
||||||
return 0, nil
|
|
||||||
case PD5: // channel B
|
|
||||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
|
|
||||||
return 1, nil
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
switch pin {
|
|
||||||
case PB1: // channel A
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1)
|
|
||||||
return 0, nil
|
|
||||||
case PB2: // channel B
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1)
|
|
||||||
return 1, nil
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
switch pin {
|
|
||||||
case PB3: // channel A
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
|
|
||||||
return 0, nil
|
|
||||||
case PD3: // channel B
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1)
|
|
||||||
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%.
|
|
||||||
//
|
|
||||||
// Note: the invert state may not be applied on the AVR until the next call to
|
|
||||||
// ch.Set().
|
|
||||||
func (pwm PWM) SetInverting(channel uint8, inverting bool) {
|
|
||||||
switch pwm.num {
|
|
||||||
case 0:
|
|
||||||
switch channel {
|
|
||||||
case 0: // channel A
|
|
||||||
if inverting {
|
|
||||||
avr.PORTB.SetBits(1 << 6) // PB6 high
|
|
||||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A0)
|
|
||||||
} else {
|
|
||||||
avr.PORTB.ClearBits(1 << 6) // PB6 low
|
|
||||||
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A0)
|
|
||||||
}
|
|
||||||
case 1: // channel B
|
|
||||||
if inverting {
|
|
||||||
avr.PORTB.SetBits(1 << 5) // PB5 high
|
|
||||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B0)
|
|
||||||
} else {
|
|
||||||
avr.PORTB.ClearBits(1 << 5) // PB5 low
|
|
||||||
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
// Note: the COM1A0/COM1B0 bit is not set with the configuration below.
|
|
||||||
// It will be set the following call to Set(), however.
|
|
||||||
switch channel {
|
|
||||||
case 0: // channel A, PB1
|
|
||||||
if inverting {
|
|
||||||
avr.PORTB.SetBits(1 << 1) // PB1 high
|
|
||||||
} else {
|
|
||||||
avr.PORTB.ClearBits(1 << 1) // PB1 low
|
|
||||||
}
|
|
||||||
case 1: // channel B, PB2
|
|
||||||
if inverting {
|
|
||||||
avr.PORTB.SetBits(1 << 2) // PB2 high
|
|
||||||
} else {
|
|
||||||
avr.PORTB.ClearBits(1 << 2) // PB2 low
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 2:
|
|
||||||
switch channel {
|
|
||||||
case 0: // channel A
|
|
||||||
if inverting {
|
|
||||||
avr.PORTB.SetBits(1 << 3) // PB3 high
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A0)
|
|
||||||
} else {
|
|
||||||
avr.PORTB.ClearBits(1 << 3) // PB3 low
|
|
||||||
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A0)
|
|
||||||
}
|
|
||||||
case 1: // channel B
|
|
||||||
if inverting {
|
|
||||||
avr.PORTD.SetBits(1 << 3) // PD3 high
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B0)
|
|
||||||
} else {
|
|
||||||
avr.PORTD.ClearBits(1 << 3) // PD3 low
|
|
||||||
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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:
|
|
||||||
value := uint16(value)
|
|
||||||
switch channel {
|
|
||||||
case 0: // channel A
|
|
||||||
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
|
|
||||||
if value == 0 {
|
|
||||||
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B1)
|
|
||||||
} else {
|
|
||||||
avr.OCR0B.Set(uint8(value) - 1)
|
|
||||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// monotonic timer is using the same time as PWM:0
|
|
||||||
// we must adust internal settings of monotonic timer when PWM:0 settings changed
|
|
||||||
adjustMonotonicTimer()
|
|
||||||
case 1:
|
|
||||||
mask := interrupt.Disable()
|
|
||||||
switch channel {
|
|
||||||
case 0: // channel A, PB1
|
|
||||||
if value == 0 {
|
|
||||||
avr.TCCR1A.ClearBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0)
|
|
||||||
} else {
|
|
||||||
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
|
|
||||||
avr.OCR1AH.Set(uint8(value >> 8))
|
|
||||||
avr.OCR1AL.Set(uint8(value))
|
|
||||||
if avr.PORTB.HasBits(1 << 1) { // is PB1 high?
|
|
||||||
// Yes, set the inverting bit.
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0)
|
|
||||||
} else {
|
|
||||||
// No, output is non-inverting.
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case 1: // channel B, PB2
|
|
||||||
if value == 0 {
|
|
||||||
avr.TCCR1A.ClearBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0)
|
|
||||||
} else {
|
|
||||||
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
|
|
||||||
avr.OCR1BH.Set(uint8(value >> 8))
|
|
||||||
avr.OCR1BL.Set(uint8(value))
|
|
||||||
if avr.PORTB.HasBits(1 << 2) { // is PB2 high?
|
|
||||||
// Yes, set the inverting bit.
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0)
|
|
||||||
} else {
|
|
||||||
// No, output is non-inverting.
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
interrupt.Restore(mask)
|
|
||||||
case 2:
|
|
||||||
value := uint16(value)
|
|
||||||
switch channel {
|
|
||||||
case 0: // channel A
|
|
||||||
if value == 0 {
|
|
||||||
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A1)
|
|
||||||
} else {
|
|
||||||
avr.OCR2A.Set(uint8(value - 1))
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
|
|
||||||
}
|
|
||||||
case 1: // channel B
|
|
||||||
if value == 0 {
|
|
||||||
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B1)
|
|
||||||
} else {
|
|
||||||
avr.OCR2B.Set(uint8(value - 1))
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SPI configuration
|
|
||||||
var SPI0 = SPI{
|
|
||||||
spcr: avr.SPCR,
|
|
||||||
spdr: avr.SPDR,
|
|
||||||
spsr: avr.SPSR,
|
|
||||||
sck: PB5,
|
|
||||||
sdo: PB3,
|
|
||||||
sdi: PB4,
|
|
||||||
cs: PB2}
|
|
||||||
|
|
||||||
// Pin Change Interrupts
|
|
||||||
type PinChange uint8
|
|
||||||
|
|
||||||
const (
|
|
||||||
PinRising PinChange = 1 << iota
|
|
||||||
PinFalling
|
|
||||||
PinToggle = PinRising | PinFalling
|
|
||||||
)
|
|
||||||
|
|
||||||
func (pin Pin) SetInterrupt(pinChange PinChange, callback func(Pin)) (err error) {
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case pin >= PB0 && pin <= PB7:
|
|
||||||
// PCMSK0 - PCINT0-7
|
|
||||||
pinStates[0] = avr.PINB.Get()
|
|
||||||
pinIndex := pin - PB0
|
|
||||||
if pinChange&PinRising > 0 {
|
|
||||||
pinCallbacks[0][pinIndex][0] = callback
|
|
||||||
}
|
|
||||||
if pinChange&PinFalling > 0 {
|
|
||||||
pinCallbacks[0][pinIndex][1] = callback
|
|
||||||
}
|
|
||||||
if callback != nil {
|
|
||||||
avr.PCMSK0.SetBits(1 << pinIndex)
|
|
||||||
} else {
|
|
||||||
avr.PCMSK0.ClearBits(1 << pinIndex)
|
|
||||||
}
|
|
||||||
avr.PCICR.SetBits(avr.PCICR_PCIE0)
|
|
||||||
interrupt.New(avr.IRQ_PCINT0, handlePCINT0Interrupts)
|
|
||||||
case pin >= PC0 && pin <= PC7:
|
|
||||||
// PCMSK1 - PCINT8-14
|
|
||||||
pinStates[1] = avr.PINC.Get()
|
|
||||||
pinIndex := pin - PC0
|
|
||||||
if pinChange&PinRising > 0 {
|
|
||||||
pinCallbacks[1][pinIndex][0] = callback
|
|
||||||
}
|
|
||||||
if pinChange&PinFalling > 0 {
|
|
||||||
pinCallbacks[1][pinIndex][1] = callback
|
|
||||||
}
|
|
||||||
if callback != nil {
|
|
||||||
avr.PCMSK1.SetBits(1 << pinIndex)
|
|
||||||
} else {
|
|
||||||
avr.PCMSK1.ClearBits(1 << pinIndex)
|
|
||||||
}
|
|
||||||
avr.PCICR.SetBits(avr.PCICR_PCIE1)
|
|
||||||
interrupt.New(avr.IRQ_PCINT1, handlePCINT1Interrupts)
|
|
||||||
case pin >= PD0 && pin <= PD7:
|
|
||||||
// PCMSK2 - PCINT16-23
|
|
||||||
pinStates[2] = avr.PIND.Get()
|
|
||||||
pinIndex := pin - PD0
|
|
||||||
if pinChange&PinRising > 0 {
|
|
||||||
pinCallbacks[2][pinIndex][0] = callback
|
|
||||||
}
|
|
||||||
if pinChange&PinFalling > 0 {
|
|
||||||
pinCallbacks[2][pinIndex][1] = callback
|
|
||||||
}
|
|
||||||
if callback != nil {
|
|
||||||
avr.PCMSK2.SetBits(1 << pinIndex)
|
|
||||||
} else {
|
|
||||||
avr.PCMSK2.ClearBits(1 << pinIndex)
|
|
||||||
}
|
|
||||||
avr.PCICR.SetBits(avr.PCICR_PCIE2)
|
|
||||||
interrupt.New(avr.IRQ_PCINT2, handlePCINT2Interrupts)
|
|
||||||
default:
|
|
||||||
return ErrInvalidInputPin
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var pinCallbacks [3][8][2]func(Pin)
|
|
||||||
var pinStates [3]uint8
|
|
||||||
|
|
||||||
func handlePCINTInterrupts(intr uint8, port *volatile.Register8) {
|
|
||||||
current := port.Get()
|
|
||||||
change := pinStates[intr] ^ current
|
|
||||||
pinStates[intr] = current
|
|
||||||
for i := uint8(0); i < 8; i++ {
|
|
||||||
if (change>>i)&0x01 != 0x01 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
pin := Pin(intr*8 + i)
|
|
||||||
value := pin.Get()
|
|
||||||
if value && pinCallbacks[intr][i][0] != nil {
|
|
||||||
pinCallbacks[intr][i][0](pin)
|
|
||||||
}
|
|
||||||
if !value && pinCallbacks[intr][i][1] != nil {
|
|
||||||
pinCallbacks[intr][i][1](pin)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func handlePCINT0Interrupts(intr interrupt.Interrupt) {
|
|
||||||
handlePCINTInterrupts(0, avr.PINB)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handlePCINT1Interrupts(intr interrupt.Interrupt) {
|
|
||||||
handlePCINTInterrupts(1, avr.PINC)
|
|
||||||
}
|
|
||||||
|
|
||||||
func handlePCINT2Interrupts(intr interrupt.Interrupt) {
|
|
||||||
handlePCINTInterrupts(2, avr.PIND)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -4,10 +4,105 @@ package machine
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"device/avr"
|
"device/avr"
|
||||||
|
"runtime/interrupt"
|
||||||
"runtime/volatile"
|
"runtime/volatile"
|
||||||
)
|
)
|
||||||
|
|
||||||
const irq_USART0_RX = avr.IRQ_USART0_RX
|
const irq_USART0_RX = avr.IRQ_USART0_RX
|
||||||
|
const irq_USART1_RX = avr.IRQ_USART1_RX
|
||||||
|
|
||||||
|
var (
|
||||||
|
UART1 = &_UART1
|
||||||
|
_UART1 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
|
||||||
|
dataReg: avr.UDR1,
|
||||||
|
baudRegH: avr.UBRR1H,
|
||||||
|
baudRegL: avr.UBRR1L,
|
||||||
|
statusRegA: avr.UCSR1A,
|
||||||
|
statusRegB: avr.UCSR1B,
|
||||||
|
statusRegC: avr.UCSR1C,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Register the UART interrupt.
|
||||||
|
interrupt.New(irq_USART1_RX, _UART1.handleInterrupt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// I2C0 is the only I2C interface on most AVRs.
|
||||||
|
var I2C0 = &I2C{
|
||||||
|
srReg: avr.TWSR0,
|
||||||
|
brReg: avr.TWBR0,
|
||||||
|
crReg: avr.TWCR0,
|
||||||
|
drReg: avr.TWDR0,
|
||||||
|
srPS0: avr.TWSR0_TWPS0,
|
||||||
|
srPS1: avr.TWSR0_TWPS1,
|
||||||
|
crEN: avr.TWCR0_TWEN,
|
||||||
|
crINT: avr.TWCR0_TWINT,
|
||||||
|
crSTO: avr.TWCR0_TWSTO,
|
||||||
|
crEA: avr.TWCR0_TWEA,
|
||||||
|
crSTA: avr.TWCR0_TWSTA,
|
||||||
|
}
|
||||||
|
|
||||||
|
var I2C1 = &I2C{
|
||||||
|
srReg: avr.TWSR1,
|
||||||
|
brReg: avr.TWBR1,
|
||||||
|
crReg: avr.TWCR1,
|
||||||
|
drReg: avr.TWDR1,
|
||||||
|
srPS0: avr.TWSR1_TWPS10,
|
||||||
|
srPS1: avr.TWSR1_TWPS11,
|
||||||
|
crEN: avr.TWCR1_TWEN1,
|
||||||
|
crINT: avr.TWCR1_TWINT1,
|
||||||
|
crSTO: avr.TWCR1_TWSTO1,
|
||||||
|
crEA: avr.TWCR1_TWEA1,
|
||||||
|
crSTA: avr.TWCR1_TWSTA1,
|
||||||
|
}
|
||||||
|
|
||||||
|
// SPI configuration
|
||||||
|
var SPI0 = SPI{
|
||||||
|
spcr: avr.SPCR0,
|
||||||
|
spdr: avr.SPDR0,
|
||||||
|
spsr: avr.SPSR0,
|
||||||
|
|
||||||
|
spcrR0: avr.SPCR0_SPR0,
|
||||||
|
spcrR1: avr.SPCR0_SPR1,
|
||||||
|
spcrCPHA: avr.SPCR0_CPHA,
|
||||||
|
spcrCPOL: avr.SPCR0_CPOL,
|
||||||
|
spcrDORD: avr.SPCR0_DORD,
|
||||||
|
spcrSPE: avr.SPCR0_SPE,
|
||||||
|
spcrMSTR: avr.SPCR0_MSTR,
|
||||||
|
|
||||||
|
spsrI2X: avr.SPSR0_SPI2X,
|
||||||
|
spsrSPIF: avr.SPSR0_SPIF,
|
||||||
|
|
||||||
|
sck: PB5,
|
||||||
|
sdo: PB3,
|
||||||
|
sdi: PB4,
|
||||||
|
cs: PB2,
|
||||||
|
}
|
||||||
|
|
||||||
|
var SPI1 = SPI{
|
||||||
|
spcr: avr.SPCR1,
|
||||||
|
spdr: avr.SPDR1,
|
||||||
|
spsr: avr.SPSR1,
|
||||||
|
|
||||||
|
spcrR0: avr.SPCR1_SPR10,
|
||||||
|
spcrR1: avr.SPCR1_SPR11,
|
||||||
|
spcrCPHA: avr.SPCR1_CPHA1,
|
||||||
|
spcrCPOL: avr.SPCR1_CPOL1,
|
||||||
|
spcrDORD: avr.SPCR1_DORD1,
|
||||||
|
spcrSPE: avr.SPCR1_SPE1,
|
||||||
|
spcrMSTR: avr.SPCR1_MSTR1,
|
||||||
|
|
||||||
|
spsrI2X: avr.SPSR1_SPI2X1,
|
||||||
|
spsrSPIF: avr.SPSR1_SPIF1,
|
||||||
|
|
||||||
|
sck: PC1,
|
||||||
|
sdo: PE3,
|
||||||
|
sdi: PC0,
|
||||||
|
cs: PE2,
|
||||||
|
}
|
||||||
|
|
||||||
// getPortMask returns the PORTx register and mask for the pin.
|
// getPortMask returns the PORTx register and mask for the pin.
|
||||||
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
||||||
@@ -16,94 +111,9 @@ func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
|||||||
return avr.PORTB, 1 << uint8(p-portB)
|
return avr.PORTB, 1 << uint8(p-portB)
|
||||||
case p >= PC0 && p <= PC7: // port C
|
case p >= PC0 && p <= PC7: // port C
|
||||||
return avr.PORTC, 1 << uint8(p-portC)
|
return avr.PORTC, 1 << uint8(p-portC)
|
||||||
default: // port D
|
case p >= PD0 && p <= PD7: // port D
|
||||||
return avr.PORTD, 1 << uint8(p-portD)
|
return avr.PORTD, 1 << uint8(p-portD)
|
||||||
|
default: // port E
|
||||||
|
return avr.PORTE, 1 << uint8(p-portE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitPWM initializes the registers needed for PWM.
|
|
||||||
func InitPWM() {
|
|
||||||
// use waveform generation
|
|
||||||
avr.TCCR0A.SetBits(avr.TCCR0A_WGM00)
|
|
||||||
|
|
||||||
// set timer 0 prescale factor to 64
|
|
||||||
avr.TCCR0B.SetBits(avr.TCCR0B_CS01 | avr.TCCR0B_CS00)
|
|
||||||
|
|
||||||
// set timer 1 prescale factor to 64
|
|
||||||
avr.TCCR1B.SetBits(avr.TCCR1B_CS11)
|
|
||||||
|
|
||||||
// put timer 1 in 8-bit phase correct pwm mode
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_WGM10)
|
|
||||||
|
|
||||||
// set timer 2 prescale factor to 64
|
|
||||||
avr.TCCR2B.SetBits(avr.TCCR2B_CS22)
|
|
||||||
|
|
||||||
// configure timer 2 for phase correct pwm (8-bit)
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_WGM20)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure configures a PWM pin for output.
|
|
||||||
func (pwm PWM) Configure() error {
|
|
||||||
switch pwm.Pin / 8 {
|
|
||||||
case 0: // port B
|
|
||||||
avr.DDRB.SetBits(1 << uint8(pwm.Pin))
|
|
||||||
case 2: // port D
|
|
||||||
avr.DDRD.SetBits(1 << uint8(pwm.Pin-16))
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set turns on the duty cycle for a PWM pin using the provided value. On the AVR this is normally a
|
|
||||||
// 8-bit value ranging from 0 to 255.
|
|
||||||
func (pwm PWM) Set(value uint16) {
|
|
||||||
value8 := uint8(value >> 8)
|
|
||||||
switch pwm.Pin {
|
|
||||||
case PD3:
|
|
||||||
// connect pwm to pin on timer 2, channel B
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1)
|
|
||||||
avr.OCR2B.Set(value8) // set pwm duty
|
|
||||||
case PD5:
|
|
||||||
// connect pwm to pin on timer 0, channel B
|
|
||||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
|
|
||||||
avr.OCR0B.Set(value8) // set pwm duty
|
|
||||||
case PD6:
|
|
||||||
// connect pwm to pin on timer 0, channel A
|
|
||||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1)
|
|
||||||
avr.OCR0A.Set(value8) // set pwm duty
|
|
||||||
case PB1:
|
|
||||||
// connect pwm to pin on timer 1, channel A
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1)
|
|
||||||
// this is a 16-bit value, but we only currently allow the low order bits to be set
|
|
||||||
avr.OCR1AL.Set(value8) // set pwm duty
|
|
||||||
case PB2:
|
|
||||||
// connect pwm to pin on timer 1, channel B
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1)
|
|
||||||
// this is a 16-bit value, but we only currently allow the low order bits to be set
|
|
||||||
avr.OCR1BL.Set(value8) // set pwm duty
|
|
||||||
case PB3:
|
|
||||||
// connect pwm to pin on timer 2, channel A
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
|
|
||||||
avr.OCR2A.Set(value8) // set pwm duty
|
|
||||||
default:
|
|
||||||
panic("Invalid PWM pin")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// SPI configuration
|
|
||||||
var SPI0 = SPI{
|
|
||||||
spcr: avr.SPCR0,
|
|
||||||
spdr: avr.SPDR0,
|
|
||||||
spsr: avr.SPSR0,
|
|
||||||
sck: PB5,
|
|
||||||
sdo: PB3,
|
|
||||||
sdi: PB4,
|
|
||||||
cs: PB2}
|
|
||||||
|
|
||||||
var SPI1 = SPI{
|
|
||||||
spcr: avr.SPCR1,
|
|
||||||
spdr: avr.SPDR1,
|
|
||||||
spsr: avr.SPSR1,
|
|
||||||
sck: PC1,
|
|
||||||
sdo: PE3,
|
|
||||||
sdi: PC0,
|
|
||||||
cs: PE2}
|
|
||||||
|
|||||||
@@ -534,16 +534,16 @@ func (uart *UART) Configure(config UARTConfig) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return ErrInvalidOutputPin
|
return ErrInvalidOutputPin
|
||||||
}
|
}
|
||||||
var txPinOut uint32
|
var txPadOut uint32
|
||||||
// See table 25-9 of the datasheet (page 459) for how pads are mapped to
|
// See table 25-9 of the datasheet (page 459) for how pads are mapped to
|
||||||
// pinout values.
|
// pinout values.
|
||||||
switch txPad {
|
switch txPad {
|
||||||
case 0:
|
case 0:
|
||||||
txPinOut = 0
|
txPadOut = 0
|
||||||
case 2:
|
case 2:
|
||||||
txPinOut = 1
|
txPadOut = 1
|
||||||
default:
|
default:
|
||||||
// TODO: flow control (RTS/CTS)
|
// this should be a flow control (RTS/CTS) pin
|
||||||
return ErrInvalidOutputPin
|
return ErrInvalidOutputPin
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,12 +554,35 @@ func (uart *UART) Configure(config UARTConfig) error {
|
|||||||
}
|
}
|
||||||
// As you can see in table 25-8 on page 459 of the datasheet, input pins
|
// As you can see in table 25-8 on page 459 of the datasheet, input pins
|
||||||
// are mapped directly.
|
// are mapped directly.
|
||||||
rxPinOut := rxPad
|
rxPadOut := rxPad
|
||||||
|
|
||||||
// configure pins
|
// configure pins
|
||||||
config.TX.Configure(PinConfig{Mode: txPinMode})
|
config.TX.Configure(PinConfig{Mode: txPinMode})
|
||||||
config.RX.Configure(PinConfig{Mode: rxPinMode})
|
config.RX.Configure(PinConfig{Mode: rxPinMode})
|
||||||
|
|
||||||
|
// configure RTS/CTS pins if provided
|
||||||
|
if config.RTS != 0 && config.CTS != 0 {
|
||||||
|
rtsPinMode, _, ok := findPinPadMapping(uart.SERCOM, config.RTS)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidOutputPin
|
||||||
|
}
|
||||||
|
|
||||||
|
ctsPinMode, _, ok := findPinPadMapping(uart.SERCOM, config.CTS)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidInputPin
|
||||||
|
}
|
||||||
|
|
||||||
|
// See table 25-9 of the datasheet (page 459) for how pads are mapped to
|
||||||
|
// pinout values.
|
||||||
|
if txPadOut == 1 {
|
||||||
|
return ErrInvalidOutputPin
|
||||||
|
}
|
||||||
|
txPadOut = 2
|
||||||
|
|
||||||
|
config.RTS.Configure(PinConfig{Mode: rtsPinMode})
|
||||||
|
config.CTS.Configure(PinConfig{Mode: ctsPinMode})
|
||||||
|
}
|
||||||
|
|
||||||
// reset SERCOM0
|
// reset SERCOM0
|
||||||
uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_CTRLA_SWRST)
|
uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_CTRLA_SWRST)
|
||||||
for uart.Bus.CTRLA.HasBits(sam.SERCOM_USART_CTRLA_SWRST) ||
|
for uart.Bus.CTRLA.HasBits(sam.SERCOM_USART_CTRLA_SWRST) ||
|
||||||
@@ -592,8 +615,8 @@ func (uart *UART) Configure(config UARTConfig) error {
|
|||||||
// set UART pads. This is not same as pins...
|
// set UART pads. This is not same as pins...
|
||||||
// SERCOM_USART_CTRLA_TXPO(txPad) |
|
// SERCOM_USART_CTRLA_TXPO(txPad) |
|
||||||
// SERCOM_USART_CTRLA_RXPO(rxPad);
|
// SERCOM_USART_CTRLA_RXPO(rxPad);
|
||||||
uart.Bus.CTRLA.SetBits((txPinOut << sam.SERCOM_USART_CTRLA_TXPO_Pos) |
|
uart.Bus.CTRLA.SetBits((txPadOut << sam.SERCOM_USART_CTRLA_TXPO_Pos) |
|
||||||
(rxPinOut << sam.SERCOM_USART_CTRLA_RXPO_Pos))
|
(rxPadOut << sam.SERCOM_USART_CTRLA_RXPO_Pos))
|
||||||
|
|
||||||
// Enable Transceiver and Receiver
|
// Enable Transceiver and Receiver
|
||||||
//sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ;
|
//sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ;
|
||||||
|
|||||||
@@ -1015,14 +1015,14 @@ func (uart *UART) Configure(config UARTConfig) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return ErrInvalidOutputPin
|
return ErrInvalidOutputPin
|
||||||
}
|
}
|
||||||
var txPinOut uint32
|
var txPadOut uint32
|
||||||
// See CTRLA.RXPO bits of the SERCOM USART peripheral (page 945-946) for how
|
// See CTRLA.RXPO bits of the SERCOM USART peripheral (page 945-946) for how
|
||||||
// pads are mapped to pinout values.
|
// pads are mapped to pinout values.
|
||||||
switch txPad {
|
switch txPad {
|
||||||
case 0:
|
case 0:
|
||||||
txPinOut = 0
|
txPadOut = 0
|
||||||
default:
|
default:
|
||||||
// TODO: flow control (RTS/CTS)
|
// should be flow control (RTS/CTS) pin
|
||||||
return ErrInvalidOutputPin
|
return ErrInvalidOutputPin
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1033,12 +1033,32 @@ func (uart *UART) Configure(config UARTConfig) error {
|
|||||||
}
|
}
|
||||||
// As you can see in the CTRLA.RXPO bits of the SERCOM USART peripheral
|
// As you can see in the CTRLA.RXPO bits of the SERCOM USART peripheral
|
||||||
// (page 945), input pins are mapped directly.
|
// (page 945), input pins are mapped directly.
|
||||||
rxPinOut := rxPad
|
rxPadOut := rxPad
|
||||||
|
|
||||||
// configure pins
|
// configure pins
|
||||||
config.TX.Configure(PinConfig{Mode: txPinMode})
|
config.TX.Configure(PinConfig{Mode: txPinMode})
|
||||||
config.RX.Configure(PinConfig{Mode: rxPinMode})
|
config.RX.Configure(PinConfig{Mode: rxPinMode})
|
||||||
|
|
||||||
|
// configure RTS/CTS pins if provided
|
||||||
|
if config.RTS != 0 && config.CTS != 0 {
|
||||||
|
rtsPinMode, _, ok := findPinPadMapping(uart.SERCOM, config.RTS)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidOutputPin
|
||||||
|
}
|
||||||
|
|
||||||
|
ctsPinMode, _, ok := findPinPadMapping(uart.SERCOM, config.CTS)
|
||||||
|
if !ok {
|
||||||
|
return ErrInvalidInputPin
|
||||||
|
}
|
||||||
|
|
||||||
|
// See CTRLA.RXPO bits of the SERCOM USART peripheral (page 945-946) for how
|
||||||
|
// pads are mapped to pinout values.
|
||||||
|
txPadOut = 2
|
||||||
|
|
||||||
|
config.RTS.Configure(PinConfig{Mode: rtsPinMode})
|
||||||
|
config.CTS.Configure(PinConfig{Mode: ctsPinMode})
|
||||||
|
}
|
||||||
|
|
||||||
// reset SERCOM
|
// reset SERCOM
|
||||||
uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_INT_CTRLA_SWRST)
|
uart.Bus.CTRLA.SetBits(sam.SERCOM_USART_INT_CTRLA_SWRST)
|
||||||
for uart.Bus.CTRLA.HasBits(sam.SERCOM_USART_INT_CTRLA_SWRST) ||
|
for uart.Bus.CTRLA.HasBits(sam.SERCOM_USART_INT_CTRLA_SWRST) ||
|
||||||
@@ -1075,8 +1095,8 @@ func (uart *UART) Configure(config UARTConfig) error {
|
|||||||
// set UART pads. This is not same as pins...
|
// set UART pads. This is not same as pins...
|
||||||
// SERCOM_USART_CTRLA_TXPO(txPad) |
|
// SERCOM_USART_CTRLA_TXPO(txPad) |
|
||||||
// SERCOM_USART_CTRLA_RXPO(rxPad);
|
// SERCOM_USART_CTRLA_RXPO(rxPad);
|
||||||
uart.Bus.CTRLA.SetBits((txPinOut << sam.SERCOM_USART_INT_CTRLA_TXPO_Pos) |
|
uart.Bus.CTRLA.SetBits((txPadOut << sam.SERCOM_USART_INT_CTRLA_TXPO_Pos) |
|
||||||
(rxPinOut << sam.SERCOM_USART_INT_CTRLA_RXPO_Pos))
|
(rxPadOut << sam.SERCOM_USART_INT_CTRLA_RXPO_Pos))
|
||||||
|
|
||||||
// Enable Transceiver and Receiver
|
// Enable Transceiver and Receiver
|
||||||
//sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ;
|
//sercom->USART.CTRLB.reg |= SERCOM_USART_CTRLB_TXEN | SERCOM_USART_CTRLB_RXEN ;
|
||||||
|
|||||||
@@ -237,13 +237,13 @@ func (p Pin) mux() *volatile.Register32 {
|
|||||||
case 27:
|
case 27:
|
||||||
return &esp.IO_MUX.GPIO27
|
return &esp.IO_MUX.GPIO27
|
||||||
case 14:
|
case 14:
|
||||||
return &esp.IO_MUX.MTMS
|
return &esp.IO_MUX.GPIO14
|
||||||
case 12:
|
case 12:
|
||||||
return &esp.IO_MUX.MTDI
|
return &esp.IO_MUX.GPIO12
|
||||||
case 13:
|
case 13:
|
||||||
return &esp.IO_MUX.MTCK
|
return &esp.IO_MUX.GPIO13
|
||||||
case 15:
|
case 15:
|
||||||
return &esp.IO_MUX.MTDO
|
return &esp.IO_MUX.GPIO15
|
||||||
case 2:
|
case 2:
|
||||||
return &esp.IO_MUX.GPIO2
|
return &esp.IO_MUX.GPIO2
|
||||||
case 0:
|
case 0:
|
||||||
@@ -255,17 +255,17 @@ func (p Pin) mux() *volatile.Register32 {
|
|||||||
case 17:
|
case 17:
|
||||||
return &esp.IO_MUX.GPIO17
|
return &esp.IO_MUX.GPIO17
|
||||||
case 9:
|
case 9:
|
||||||
return &esp.IO_MUX.SD_DATA2
|
return &esp.IO_MUX.GPIO9
|
||||||
case 10:
|
case 10:
|
||||||
return &esp.IO_MUX.SD_DATA3
|
return &esp.IO_MUX.GPIO10
|
||||||
case 11:
|
case 11:
|
||||||
return &esp.IO_MUX.SD_CMD
|
return &esp.IO_MUX.GPIO11
|
||||||
case 6:
|
case 6:
|
||||||
return &esp.IO_MUX.SD_CLK
|
return &esp.IO_MUX.GPIO6
|
||||||
case 7:
|
case 7:
|
||||||
return &esp.IO_MUX.SD_DATA0
|
return &esp.IO_MUX.GPIO7
|
||||||
case 8:
|
case 8:
|
||||||
return &esp.IO_MUX.SD_DATA1
|
return &esp.IO_MUX.GPIO8
|
||||||
case 5:
|
case 5:
|
||||||
return &esp.IO_MUX.GPIO5
|
return &esp.IO_MUX.GPIO5
|
||||||
case 18:
|
case 18:
|
||||||
@@ -279,9 +279,9 @@ func (p Pin) mux() *volatile.Register32 {
|
|||||||
case 22:
|
case 22:
|
||||||
return &esp.IO_MUX.GPIO22
|
return &esp.IO_MUX.GPIO22
|
||||||
case 3:
|
case 3:
|
||||||
return &esp.IO_MUX.U0RXD
|
return &esp.IO_MUX.GPIO3
|
||||||
case 1:
|
case 1:
|
||||||
return &esp.IO_MUX.U0TXD
|
return &esp.IO_MUX.GPIO1
|
||||||
case 23:
|
case 23:
|
||||||
return &esp.IO_MUX.GPIO23
|
return &esp.IO_MUX.GPIO23
|
||||||
case 24:
|
case 24:
|
||||||
@@ -320,7 +320,8 @@ func (uart *UART) writeByte(b byte) error {
|
|||||||
// many bytes there are in the transmit buffer. Wait until there are
|
// many bytes there are in the transmit buffer. Wait until there are
|
||||||
// less than 128 bytes in this buffer (the default buffer size).
|
// less than 128 bytes in this buffer (the default buffer size).
|
||||||
}
|
}
|
||||||
uart.Bus.TX_FIFO.Set(b)
|
// Write to the TX_FIFO register.
|
||||||
|
(*volatile.Register8)(unsafe.Add(unsafe.Pointer(uart.Bus), 0x200C0000)).Set(b)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -111,6 +111,10 @@ func (p Pin) outFunc() *volatile.Register32 {
|
|||||||
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_OUT_SEL_CFG), uintptr(p)*4))
|
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(&esp.GPIO.FUNC0_OUT_SEL_CFG), uintptr(p)*4))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p Pin) pinReg() *volatile.Register32 {
|
||||||
|
return (*volatile.Register32)(unsafe.Pointer((uintptr(unsafe.Pointer(&esp.GPIO.PIN0)) + uintptr(p)*4)))
|
||||||
|
}
|
||||||
|
|
||||||
// inFunc returns the FUNCy_IN_SEL_CFG register used for configuring the input
|
// inFunc returns the FUNCy_IN_SEL_CFG register used for configuring the input
|
||||||
// function selection.
|
// function selection.
|
||||||
func inFunc(signal uint32) *volatile.Register32 {
|
func inFunc(signal uint32) *volatile.Register32 {
|
||||||
@@ -188,7 +192,7 @@ func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) (err error) {
|
|||||||
|
|
||||||
if callback == nil {
|
if callback == nil {
|
||||||
// Disable this pin interrupt
|
// Disable this pin interrupt
|
||||||
p.pin().ClearBits(esp.GPIO_PIN_PIN_INT_TYPE_Msk | esp.GPIO_PIN_PIN_INT_ENA_Msk)
|
p.pin().ClearBits(esp.GPIO_PIN_INT_TYPE_Msk | esp.GPIO_PIN_INT_ENA_Msk)
|
||||||
|
|
||||||
if pinCallbacks[p] != nil {
|
if pinCallbacks[p] != nil {
|
||||||
pinCallbacks[p] = nil
|
pinCallbacks[p] = nil
|
||||||
@@ -212,8 +216,8 @@ func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
p.pin().Set(
|
p.pin().Set(
|
||||||
(p.pin().Get() & ^uint32(esp.GPIO_PIN_PIN_INT_TYPE_Msk|esp.GPIO_PIN_PIN_INT_ENA_Msk)) |
|
(p.pin().Get() & ^uint32(esp.GPIO_PIN_INT_TYPE_Msk|esp.GPIO_PIN_INT_ENA_Msk)) |
|
||||||
uint32(change)<<esp.GPIO_PIN_PIN_INT_TYPE_Pos | uint32(1)<<esp.GPIO_PIN_PIN_INT_ENA_Pos)
|
uint32(change)<<esp.GPIO_PIN_INT_TYPE_Pos | uint32(1)<<esp.GPIO_PIN_INT_ENA_Pos)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -391,7 +395,7 @@ func initUARTClock(bus *esp.UART_Type, regs registerSet) {
|
|||||||
// synchronize core register
|
// synchronize core register
|
||||||
bus.SetID_REG_UPDATE(0)
|
bus.SetID_REG_UPDATE(0)
|
||||||
// enable RTC clock
|
// enable RTC clock
|
||||||
esp.RTC_CNTL.SetRTC_CLK_CONF_DIG_CLK8M_EN(1)
|
esp.RTC_CNTL.SetCLK_CONF_DIG_CLK8M_EN(1)
|
||||||
// wait for Core Clock to ready for configuration
|
// wait for Core Clock to ready for configuration
|
||||||
for bus.GetID_REG_UPDATE() > 0 {
|
for bus.GetID_REG_UPDATE() > 0 {
|
||||||
riscv.Asm("nop")
|
riscv.Asm("nop")
|
||||||
@@ -415,7 +419,7 @@ func (uart *UART) setupPins(config UARTConfig, regs registerSet) {
|
|||||||
// link TX with GPIO signal X (technical reference manual 5.10) (this is not interrupt signal!)
|
// link TX with GPIO signal X (technical reference manual 5.10) (this is not interrupt signal!)
|
||||||
config.TX.outFunc().Set(regs.gpioMatrixSignal)
|
config.TX.outFunc().Set(regs.gpioMatrixSignal)
|
||||||
// link RX with GPIO signal X and route signals via GPIO matrix (GPIO_SIGn_IN_SEL 0x40)
|
// link RX with GPIO signal X and route signals via GPIO matrix (GPIO_SIGn_IN_SEL 0x40)
|
||||||
inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SIG_IN_SEL | uint32(config.RX))
|
inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.RX))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (uart *UART) configureInterrupt(intrMapReg *volatile.Register32) { // Disable all UART interrupts
|
func (uart *UART) configureInterrupt(intrMapReg *volatile.Register32) { // Disable all UART interrupts
|
||||||
@@ -504,3 +508,130 @@ func (uart *UART) writeByte(b byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (uart *UART) flush() {}
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
// For maximum entropy also make sure that the SAR_ADC is enabled.
|
||||||
|
// See esp32-c3_technical_reference_manual_en.pdf p.524
|
||||||
|
func GetRNG() (ret uint32, err error) {
|
||||||
|
// ensure ADC clock is initialized
|
||||||
|
initADCClock()
|
||||||
|
|
||||||
|
// ensure fast RTC clock is enabled
|
||||||
|
if esp.RTC_CNTL.GetCLK_CONF_DIG_CLK8M_EN() == 0 {
|
||||||
|
esp.RTC_CNTL.SetCLK_CONF_DIG_CLK8M_EN(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return esp.APB_CTRL.GetRND_DATA(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initADCClock() {
|
||||||
|
if esp.APB_SARADC.GetCLKM_CONF_CLK_EN() == 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// only support ADC_CTRL_CLK set to 1
|
||||||
|
esp.APB_SARADC.SetCLKM_CONF_CLK_SEL(1)
|
||||||
|
|
||||||
|
esp.APB_SARADC.SetCTRL_SARADC_SAR_CLK_GATED(1)
|
||||||
|
|
||||||
|
esp.APB_SARADC.SetCLKM_CONF_CLKM_DIV_NUM(15)
|
||||||
|
esp.APB_SARADC.SetCLKM_CONF_CLKM_DIV_B(1)
|
||||||
|
esp.APB_SARADC.SetCLKM_CONF_CLKM_DIV_A(0)
|
||||||
|
|
||||||
|
esp.APB_SARADC.SetCTRL_SARADC_SAR_CLK_DIV(1)
|
||||||
|
esp.APB_SARADC.SetCLKM_CONF_CLK_EN(1)
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,353 @@
|
|||||||
|
//go:build esp32c3 && !m5stamp_c3
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/esp"
|
||||||
|
"runtime/volatile"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
I2C0 = &I2C{}
|
||||||
|
)
|
||||||
|
|
||||||
|
type I2C struct{}
|
||||||
|
|
||||||
|
// I2CConfig is used to store config info for I2C.
|
||||||
|
type I2CConfig struct {
|
||||||
|
Frequency uint32 // in Hz
|
||||||
|
SCL Pin
|
||||||
|
SDA Pin
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
clkXTAL = 0
|
||||||
|
clkFOSC = 1
|
||||||
|
clkXTALFrequency = uint32(40e6)
|
||||||
|
clkFOSCFrequency = uint32(17.5e6)
|
||||||
|
i2cClkSourceFrequency = clkXTALFrequency
|
||||||
|
i2cClkSource = clkXTAL
|
||||||
|
)
|
||||||
|
|
||||||
|
func (i2c *I2C) Configure(config I2CConfig) error {
|
||||||
|
if config.Frequency == 0 {
|
||||||
|
config.Frequency = 400 * KHz
|
||||||
|
}
|
||||||
|
if config.SCL == 0 {
|
||||||
|
config.SCL = SCL_PIN
|
||||||
|
}
|
||||||
|
if config.SDA == 0 {
|
||||||
|
config.SDA = SDA_PIN
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c.initClock(config)
|
||||||
|
i2c.initNoiseFilter()
|
||||||
|
i2c.initPins(config)
|
||||||
|
i2c.initFrequency(config)
|
||||||
|
i2c.startMaster()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (i2c *I2C) initClock(config I2CConfig) {
|
||||||
|
// reset I2C clock
|
||||||
|
esp.SYSTEM.SetPERIP_RST_EN0_I2C_EXT0_RST(1)
|
||||||
|
esp.SYSTEM.SetPERIP_CLK_EN0_I2C_EXT0_CLK_EN(1)
|
||||||
|
esp.SYSTEM.SetPERIP_RST_EN0_I2C_EXT0_RST(0)
|
||||||
|
// disable interrupts
|
||||||
|
esp.I2C0.INT_ENA.ClearBits(0x3fff)
|
||||||
|
esp.I2C0.INT_CLR.ClearBits(0x3fff)
|
||||||
|
|
||||||
|
esp.I2C0.SetCLK_CONF_SCLK_SEL(i2cClkSource)
|
||||||
|
esp.I2C0.SetCLK_CONF_SCLK_ACTIVE(1)
|
||||||
|
esp.I2C0.SetCLK_CONF_SCLK_DIV_NUM(i2cClkSourceFrequency / (config.Frequency * 1024))
|
||||||
|
esp.I2C0.SetCTR_CLK_EN(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (i2c *I2C) initNoiseFilter() {
|
||||||
|
esp.I2C0.FILTER_CFG.Set(0x377)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (i2c *I2C) initPins(config I2CConfig) {
|
||||||
|
var muxConfig uint32
|
||||||
|
const function = 1 // function 1 is just GPIO
|
||||||
|
|
||||||
|
// SDA
|
||||||
|
muxConfig = function << esp.IO_MUX_GPIO_MCU_SEL_Pos
|
||||||
|
// Make this pin an input pin (always).
|
||||||
|
muxConfig |= esp.IO_MUX_GPIO_FUN_IE
|
||||||
|
// Set drive strength: 0 is lowest, 3 is highest.
|
||||||
|
muxConfig |= 1 << esp.IO_MUX_GPIO_FUN_DRV_Pos
|
||||||
|
config.SDA.mux().Set(muxConfig)
|
||||||
|
config.SDA.outFunc().Set(54)
|
||||||
|
inFunc(54).Set(uint32(esp.GPIO_FUNC_IN_SEL_CFG_SEL | config.SDA))
|
||||||
|
config.SDA.Set(true)
|
||||||
|
// Configure the pad with the given IO mux configuration.
|
||||||
|
config.SDA.pinReg().SetBits(esp.GPIO_PIN_PAD_DRIVER)
|
||||||
|
|
||||||
|
esp.GPIO.ENABLE.SetBits(1 << int(config.SDA))
|
||||||
|
esp.I2C0.SetCTR_SDA_FORCE_OUT(1)
|
||||||
|
|
||||||
|
// SCL
|
||||||
|
muxConfig = function << esp.IO_MUX_GPIO_MCU_SEL_Pos
|
||||||
|
// Make this pin an input pin (always).
|
||||||
|
muxConfig |= esp.IO_MUX_GPIO_FUN_IE
|
||||||
|
// Set drive strength: 0 is lowest, 3 is highest.
|
||||||
|
muxConfig |= 1 << esp.IO_MUX_GPIO_FUN_DRV_Pos
|
||||||
|
config.SCL.mux().Set(muxConfig)
|
||||||
|
config.SCL.outFunc().Set(53)
|
||||||
|
inFunc(53).Set(uint32(config.SCL))
|
||||||
|
config.SCL.Set(true)
|
||||||
|
// Configure the pad with the given IO mux configuration.
|
||||||
|
config.SCL.pinReg().SetBits(esp.GPIO_PIN_PAD_DRIVER)
|
||||||
|
|
||||||
|
esp.GPIO.ENABLE.SetBits(1 << int(config.SCL))
|
||||||
|
esp.I2C0.SetCTR_SCL_FORCE_OUT(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (i2c *I2C) initFrequency(config I2CConfig) {
|
||||||
|
|
||||||
|
clkmDiv := i2cClkSourceFrequency/(config.Frequency*1024) + 1
|
||||||
|
sclkFreq := i2cClkSourceFrequency / clkmDiv
|
||||||
|
halfCycle := sclkFreq / config.Frequency / 2
|
||||||
|
//SCL
|
||||||
|
sclLow := halfCycle
|
||||||
|
sclWaitHigh := uint32(0)
|
||||||
|
if config.Frequency > 50000 {
|
||||||
|
sclWaitHigh = halfCycle / 8 // compensate the time when freq > 50K
|
||||||
|
}
|
||||||
|
sclHigh := halfCycle - sclWaitHigh
|
||||||
|
// SDA
|
||||||
|
sdaHold := halfCycle / 4
|
||||||
|
sda_sample := halfCycle / 2
|
||||||
|
setup := halfCycle
|
||||||
|
hold := halfCycle
|
||||||
|
|
||||||
|
esp.I2C0.SetSCL_LOW_PERIOD(sclLow - 1)
|
||||||
|
esp.I2C0.SetSCL_HIGH_PERIOD(sclHigh)
|
||||||
|
esp.I2C0.SetSCL_HIGH_PERIOD_SCL_WAIT_HIGH_PERIOD(25)
|
||||||
|
esp.I2C0.SetSCL_RSTART_SETUP_TIME(setup)
|
||||||
|
esp.I2C0.SetSCL_STOP_SETUP_TIME(setup)
|
||||||
|
esp.I2C0.SetSCL_START_HOLD_TIME(hold - 1)
|
||||||
|
esp.I2C0.SetSCL_STOP_HOLD_TIME(hold - 1)
|
||||||
|
esp.I2C0.SetSDA_SAMPLE_TIME(sda_sample)
|
||||||
|
esp.I2C0.SetSDA_HOLD_TIME(sdaHold)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (i2c *I2C) startMaster() {
|
||||||
|
// FIFO mode for data
|
||||||
|
esp.I2C0.SetFIFO_CONF_NONFIFO_EN(0)
|
||||||
|
// Reset TX & RX buffers
|
||||||
|
esp.I2C0.SetFIFO_CONF_RX_FIFO_RST(1)
|
||||||
|
esp.I2C0.SetFIFO_CONF_RX_FIFO_RST(0)
|
||||||
|
esp.I2C0.SetFIFO_CONF_TX_FIFO_RST(1)
|
||||||
|
esp.I2C0.SetFIFO_CONF_TX_FIFO_RST(0)
|
||||||
|
// set timeout value
|
||||||
|
esp.I2C0.TO.Set(0x10)
|
||||||
|
// enable master mode
|
||||||
|
esp.I2C0.CTR.Set(0x113)
|
||||||
|
esp.I2C0.SetCTR_CONF_UPGATE(1)
|
||||||
|
resetMaster()
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func resetMaster() {
|
||||||
|
// reset FSM
|
||||||
|
esp.I2C0.SetCTR_FSM_RST(1)
|
||||||
|
// clear the bus
|
||||||
|
esp.I2C0.SetSCL_SP_CONF_SCL_RST_SLV_NUM(9)
|
||||||
|
esp.I2C0.SetSCL_SP_CONF_SCL_RST_SLV_EN(1)
|
||||||
|
esp.I2C0.SetSCL_STRETCH_CONF_SLAVE_SCL_STRETCH_EN(1)
|
||||||
|
esp.I2C0.SetCTR_CONF_UPGATE(1)
|
||||||
|
esp.I2C0.FILTER_CFG.Set(0x377)
|
||||||
|
// wait for SCL_RST_SLV_EN
|
||||||
|
for esp.I2C0.GetSCL_SP_CONF_SCL_RST_SLV_EN() != 0 {
|
||||||
|
}
|
||||||
|
esp.I2C0.SetSCL_SP_CONF_SCL_RST_SLV_NUM(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
type i2cCommandType = uint32
|
||||||
|
type i2cAck = uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
i2cCMD_RSTART i2cCommandType = 6 << 11
|
||||||
|
i2cCMD_WRITE i2cCommandType = 1<<11 | 1<<8 // WRITE + ack_check_en
|
||||||
|
i2cCMD_READ i2cCommandType = 3<<11 | 1<<8 // READ + ack_check_en
|
||||||
|
i2cCMD_READLAST i2cCommandType = 3<<11 | 5<<8 // READ + ack_check_en + NACK
|
||||||
|
i2cCMD_STOP i2cCommandType = 2 << 11
|
||||||
|
i2cCMD_END i2cCommandType = 4 << 11
|
||||||
|
)
|
||||||
|
|
||||||
|
type i2cCommand struct {
|
||||||
|
cmd i2cCommandType
|
||||||
|
data []byte
|
||||||
|
head int
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname nanotime runtime.nanotime
|
||||||
|
func nanotime() int64
|
||||||
|
|
||||||
|
func (i2c *I2C) transmit(addr uint16, cmd []i2cCommand, timeoutMS int) error {
|
||||||
|
const intMask = esp.I2C_INT_STATUS_END_DETECT_INT_ST_Msk | esp.I2C_INT_STATUS_TRANS_COMPLETE_INT_ST_Msk | esp.I2C_INT_STATUS_TIME_OUT_INT_ST_Msk | esp.I2C_INT_STATUS_NACK_INT_ST_Msk
|
||||||
|
esp.I2C0.INT_CLR.SetBits(intMask)
|
||||||
|
esp.I2C0.INT_ENA.SetBits(intMask)
|
||||||
|
esp.I2C0.SetCTR_CONF_UPGATE(1)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
esp.I2C0.INT_CLR.SetBits(intMask)
|
||||||
|
esp.I2C0.INT_ENA.ClearBits(intMask)
|
||||||
|
}()
|
||||||
|
|
||||||
|
timeoutNS := int64(timeoutMS) * 1000000
|
||||||
|
needAddress := true
|
||||||
|
needRestart := false
|
||||||
|
readLast := false
|
||||||
|
var readTo []byte
|
||||||
|
for cmdIdx, reg := 0, &esp.I2C0.COMD0; cmdIdx < len(cmd); {
|
||||||
|
c := &cmd[cmdIdx]
|
||||||
|
|
||||||
|
switch c.cmd {
|
||||||
|
case i2cCMD_RSTART:
|
||||||
|
reg.Set(i2cCMD_RSTART)
|
||||||
|
reg = nextAddress(reg)
|
||||||
|
cmdIdx++
|
||||||
|
|
||||||
|
case i2cCMD_WRITE:
|
||||||
|
count := 32
|
||||||
|
if needAddress {
|
||||||
|
needAddress = false
|
||||||
|
esp.I2C0.SetDATA_FIFO_RDATA((uint32(addr) & 0x7f) << 1)
|
||||||
|
count--
|
||||||
|
esp.I2C0.SLAVE_ADDR.Set(uint32(addr))
|
||||||
|
esp.I2C0.SetCTR_CONF_UPGATE(1)
|
||||||
|
}
|
||||||
|
for ; count > 0 && c.head < len(c.data); count, c.head = count-1, c.head+1 {
|
||||||
|
esp.I2C0.SetDATA_FIFO_RDATA(uint32(c.data[c.head]))
|
||||||
|
}
|
||||||
|
reg.Set(i2cCMD_WRITE | uint32(32-count))
|
||||||
|
reg = nextAddress(reg)
|
||||||
|
|
||||||
|
if c.head < len(c.data) {
|
||||||
|
reg.Set(i2cCMD_END)
|
||||||
|
reg = nil
|
||||||
|
} else {
|
||||||
|
cmdIdx++
|
||||||
|
}
|
||||||
|
needRestart = true
|
||||||
|
|
||||||
|
case i2cCMD_READ:
|
||||||
|
if needAddress {
|
||||||
|
needAddress = false
|
||||||
|
esp.I2C0.SetDATA_FIFO_RDATA((uint32(addr)&0x7f)<<1 | 1)
|
||||||
|
esp.I2C0.SLAVE_ADDR.Set(uint32(addr))
|
||||||
|
reg.Set(i2cCMD_WRITE | 1)
|
||||||
|
reg = nextAddress(reg)
|
||||||
|
}
|
||||||
|
if needRestart {
|
||||||
|
// We need to send RESTART again after i2cCMD_WRITE.
|
||||||
|
reg.Set(i2cCMD_RSTART)
|
||||||
|
|
||||||
|
reg = nextAddress(reg)
|
||||||
|
reg.Set(i2cCMD_WRITE | 1)
|
||||||
|
|
||||||
|
reg = nextAddress(reg)
|
||||||
|
esp.I2C0.SetDATA_FIFO_RDATA((uint32(addr)&0x7f)<<1 | 1)
|
||||||
|
needRestart = false
|
||||||
|
}
|
||||||
|
count := 32
|
||||||
|
bytes := len(c.data) - c.head
|
||||||
|
// Only last byte in sequence must be sent with ACK set to 1 to indicate end of data.
|
||||||
|
split := bytes <= count
|
||||||
|
if split {
|
||||||
|
bytes--
|
||||||
|
}
|
||||||
|
if bytes > 32 {
|
||||||
|
bytes = 32
|
||||||
|
}
|
||||||
|
reg.Set(i2cCMD_READ | uint32(bytes))
|
||||||
|
reg = nextAddress(reg)
|
||||||
|
|
||||||
|
if split {
|
||||||
|
readLast = true
|
||||||
|
reg.Set(i2cCMD_READLAST | 1)
|
||||||
|
reg = nextAddress(reg)
|
||||||
|
readTo = c.data[c.head : c.head+bytes+1] // read bytes + 1 last byte
|
||||||
|
cmdIdx++
|
||||||
|
} else {
|
||||||
|
reg.Set(i2cCMD_END)
|
||||||
|
readTo = c.data[c.head : c.head+bytes]
|
||||||
|
reg = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
case i2cCMD_STOP:
|
||||||
|
reg.Set(i2cCMD_STOP)
|
||||||
|
reg = nil
|
||||||
|
cmdIdx++
|
||||||
|
}
|
||||||
|
if reg == nil {
|
||||||
|
// transmit now
|
||||||
|
esp.I2C0.SetCTR_CONF_UPGATE(1)
|
||||||
|
esp.I2C0.SetCTR_TRANS_START(1)
|
||||||
|
end := nanotime() + timeoutNS
|
||||||
|
var mask uint32
|
||||||
|
for mask = esp.I2C0.INT_STATUS.Get(); mask&intMask == 0; mask = esp.I2C0.INT_STATUS.Get() {
|
||||||
|
if nanotime() > end {
|
||||||
|
if readTo != nil {
|
||||||
|
return errI2CReadTimeout
|
||||||
|
}
|
||||||
|
return errI2CWriteTimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case mask&esp.I2C_INT_STATUS_NACK_INT_ST_Msk != 0 && !readLast:
|
||||||
|
return errI2CAckExpected
|
||||||
|
case mask&esp.I2C_INT_STATUS_TIME_OUT_INT_ST_Msk != 0:
|
||||||
|
if readTo != nil {
|
||||||
|
return errI2CReadTimeout
|
||||||
|
}
|
||||||
|
return errI2CWriteTimeout
|
||||||
|
}
|
||||||
|
esp.I2C0.INT_CLR.SetBits(intMask)
|
||||||
|
for i := 0; i < len(readTo); i++ {
|
||||||
|
readTo[i] = byte(esp.I2C0.GetDATA_FIFO_RDATA() & 0xff)
|
||||||
|
c.head++
|
||||||
|
}
|
||||||
|
readTo = nil
|
||||||
|
reg = &esp.I2C0.COMD0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tx does a single I2C transaction at the specified address.
|
||||||
|
// It clocks out the given address, writes the bytes in w, reads back len(r)
|
||||||
|
// bytes and stores them in r, and generates a stop condition on the bus.
|
||||||
|
func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) {
|
||||||
|
// timeout in microseconds.
|
||||||
|
const timeout = 40 // 40ms is a reasonable time for a real-time system.
|
||||||
|
|
||||||
|
cmd := make([]i2cCommand, 0, 8)
|
||||||
|
cmd = append(cmd, i2cCommand{cmd: i2cCMD_RSTART})
|
||||||
|
if len(w) > 0 {
|
||||||
|
cmd = append(cmd, i2cCommand{cmd: i2cCMD_WRITE, data: w})
|
||||||
|
}
|
||||||
|
if len(r) > 0 {
|
||||||
|
cmd = append(cmd, i2cCommand{cmd: i2cCMD_READ, data: r})
|
||||||
|
}
|
||||||
|
cmd = append(cmd, i2cCommand{cmd: i2cCMD_STOP})
|
||||||
|
|
||||||
|
return i2c.transmit(addr, cmd, timeout)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i2c *I2C) SetBaudRate(br uint32) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func nextAddress(reg *volatile.Register32) *volatile.Register32 {
|
||||||
|
return (*volatile.Register32)(unsafe.Add(unsafe.Pointer(reg), 4))
|
||||||
|
}
|
||||||
@@ -201,7 +201,7 @@ func (spi SPI) Configure(config SPIConfig) error {
|
|||||||
|
|
||||||
// configure esp32c3 gpio pin matrix
|
// configure esp32c3 gpio pin matrix
|
||||||
config.SDI.Configure(PinConfig{Mode: PinInput})
|
config.SDI.Configure(PinConfig{Mode: PinInput})
|
||||||
inFunc(FSPIQ_IN_IDX).Set(esp.GPIO_FUNC_IN_SEL_CFG_SIG_IN_SEL | uint32(config.SDI))
|
inFunc(FSPIQ_IN_IDX).Set(esp.GPIO_FUNC_IN_SEL_CFG_SEL | uint32(config.SDI))
|
||||||
config.SDO.Configure(PinConfig{Mode: PinOutput})
|
config.SDO.Configure(PinConfig{Mode: PinOutput})
|
||||||
config.SDO.outFunc().Set(FSPID_OUT_IDX)
|
config.SDO.outFunc().Set(FSPID_OUT_IDX)
|
||||||
config.SCK.Configure(PinConfig{Mode: PinOutput})
|
config.SCK.Configure(PinConfig{Mode: PinOutput})
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build nrf52840 && nrf52840_lfxtal_false
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
const HasLowFrequencyCrystal = false
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
//go:build nrf52840 && ((nrf52840_generic && !nrf52840_lfxtal_false) || nrf52840_lfxtal_true)
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
const HasLowFrequencyCrystal = true
|
||||||
@@ -241,6 +241,8 @@ const (
|
|||||||
PinFalling PinChange = 4 << iota
|
PinFalling PinChange = 4 << iota
|
||||||
// Edge rising
|
// Edge rising
|
||||||
PinRising
|
PinRising
|
||||||
|
|
||||||
|
PinToggle = PinFalling | PinRising
|
||||||
)
|
)
|
||||||
|
|
||||||
// Callbacks to be called for pins configured with SetInterrupt.
|
// Callbacks to be called for pins configured with SetInterrupt.
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user