Compare commits

..

1 Commits

Author SHA1 Message Date
Ayke van Laethem c660750636 tools: process SVD files in parallel
This speeds up the generation of SVD files, for example as part of a
package build (where parallelism may not be desired, or tools should
auto-detect the number of threads to use).
2023-10-04 15:24:09 +02:00
84 changed files with 488 additions and 1510 deletions
+7 -16
View File
@@ -5,7 +5,7 @@ commands:
steps: steps:
- run: - run:
name: "Pull submodules" name: "Pull submodules"
command: git submodule update --init --recursive command: git submodule update --init
llvm-source-linux: llvm-source-linux:
steps: steps:
- restore_cache: - restore_cache:
@@ -55,7 +55,7 @@ commands:
- run: - run:
name: "Install apt dependencies" name: "Install apt dependencies"
command: | command: |
echo 'deb https://apt.llvm.org/bullseye/ llvm-toolchain-bullseye-<<parameters.llvm>> main' > /etc/apt/sources.list.d/llvm.list echo 'deb https://apt.llvm.org/buster/ llvm-toolchain-buster-<<parameters.llvm>> main' > /etc/apt/sources.list.d/llvm.list
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
apt-get update apt-get update
apt-get install --no-install-recommends -y \ apt-get install --no-install-recommends -y \
@@ -69,8 +69,8 @@ commands:
- build-binaryen-linux - build-binaryen-linux
- restore_cache: - restore_cache:
keys: keys:
- go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }} - go-cache-v3-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-v4-{{ checksum "go.mod" }} - go-cache-v3-{{ checksum "go.mod" }}
- llvm-source-linux - llvm-source-linux
- run: go install -tags=llvm<<parameters.llvm>> . - run: go install -tags=llvm<<parameters.llvm>> .
- restore_cache: - restore_cache:
@@ -89,10 +89,10 @@ commands:
# formatting of generated files. # formatting of generated files.
name: Check Go code formatting name: Check Go code formatting
command: make fmt-check command: make fmt-check
- run: make gen-device -j4 - run: make gen-device
- run: make smoketest XTENSA=0 - run: make smoketest XTENSA=0
- save_cache: - save_cache:
key: go-cache-v4-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }} key: go-cache-v3-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
paths: paths:
- ~/.cache/go-build - ~/.cache/go-build
- /go/pkg/mod - /go/pkg/mod
@@ -100,18 +100,11 @@ commands:
jobs: jobs:
test-llvm15-go118: test-llvm15-go118:
docker: docker:
- image: golang:1.18-bullseye - image: golang:1.18-buster
steps: steps:
- test-linux: - test-linux:
llvm: "15" llvm: "15"
resource_class: large resource_class: large
test-llvm17-go121:
docker:
- image: golang:1.21-bullseye
steps:
- test-linux:
llvm: "17"
resource_class: large
workflows: workflows:
test-all: test-all:
@@ -119,5 +112,3 @@ 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.
- test-llvm17-go121
+4 -20
View File
@@ -88,7 +88,7 @@ jobs:
if: steps.cache-wasi-libc.outputs.cache-hit != 'true' if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
run: make wasi-libc run: make wasi-libc
- name: make gen-device - name: make gen-device
run: make -j3 gen-device run: make gen-device
- name: Test TinyGo - name: Test TinyGo
shell: bash shell: bash
run: make test GOTESTFLAGS="-short" run: make test GOTESTFLAGS="-short"
@@ -116,21 +116,11 @@ jobs:
test-macos-homebrew: test-macos-homebrew:
name: homebrew-install name: homebrew-install
runs-on: macos-latest runs-on: macos-latest
strategy:
matrix:
version: [16, 17]
steps: steps:
- name: Update Homebrew
run: brew update
- name: Fix Python symlinks
run: |
# Github runners have broken symlinks, so relink
# see: https://github.com/actions/setup-python/issues/577
brew unlink python
brew link --overwrite python
- name: Install LLVM - name: Install LLVM
shell: bash
run: | run: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.version }} HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@16
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Install Go - name: Install Go
@@ -138,13 +128,7 @@ jobs:
with: with:
go-version: '1.21' go-version: '1.21'
cache: true cache: true
- name: Build TinyGo (LLVM ${{ matrix.version }}) - name: Build TinyGo
run: go install -tags=llvm${{ matrix.version }}
- name: Check binary
run: tinygo version
- name: Build TinyGo (default LLVM)
if: matrix.version == 16
run: go install run: go install
- name: Check binary - name: Check binary
if: matrix.version == 16
run: tinygo version run: tinygo version
+7 -7
View File
@@ -140,8 +140,8 @@ jobs:
- name: Install wasmtime - name: Install wasmtime
run: | run: |
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
curl https://github.com/bytecodealliance/wasmtime/releases/download/v14.0.4/wasmtime-v14.0.4-x86_64-linux.tar.xz -o wasmtime-v14.0.4-x86_64-linux.tar.xz -SfL curl https://github.com/bytecodealliance/wasmtime/releases/download/v5.0.0/wasmtime-v5.0.0-x86_64-linux.tar.xz -o wasmtime-v5.0.0-x86_64-linux.tar.xz -SfL
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-v5.0.0-x86_64-linux.tar.xz --strip-components=1 wasmtime-v5.0.0-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@v3
@@ -187,8 +187,8 @@ jobs:
- name: Install wasmtime - name: Install wasmtime
run: | run: |
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v14.0.4/wasmtime-v14.0.4-x86_64-linux.tar.xz -o wasmtime-v14.0.4-x86_64-linux.tar.xz -SfL curl -L https://github.com/bytecodealliance/wasmtime/releases/download/v5.0.0/wasmtime-v5.0.0-x86_64-linux.tar.xz -o wasmtime-v5.0.0-x86_64-linux.tar.xz -SfL
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-v5.0.0-x86_64-linux.tar.xz --strip-components=1 wasmtime-v5.0.0-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@v3
@@ -255,7 +255,7 @@ jobs:
- 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'
run: make wasi-libc run: make wasi-libc
- run: make gen-device -j4 - run: make gen-device
- name: Test TinyGo - name: Test TinyGo
run: make ASSERT=1 test run: make ASSERT=1 test
- name: Build TinyGo - name: Build TinyGo
@@ -356,13 +356,13 @@ jobs:
uses: actions/cache@v3 uses: actions/cache@v3
id: cache-binaryen id: cache-binaryen
with: with:
key: binaryen-linux-${{ matrix.goarch }}-v3 key: binaryen-linux-${{ matrix.goarch }}-v1
path: build/wasm-opt path: build/wasm-opt
- name: Build Binaryen - name: Build Binaryen
if: steps.cache-binaryen.outputs.cache-hit != 'true' if: steps.cache-binaryen.outputs.cache-hit != 'true'
run: | run: |
sudo apt-get install --no-install-recommends ninja-build sudo apt-get install --no-install-recommends ninja-build
git submodule update --init --recursive lib/binaryen git submodule update --init lib/binaryen
make CROSS=${{ matrix.toolchain }} binaryen make CROSS=${{ matrix.toolchain }} binaryen
- name: Install fpm - name: Install fpm
run: | run: |
-43
View File
@@ -1,43 +0,0 @@
name: Nix
on:
pull_request:
push:
branches:
- dev
- release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
nix-test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Pull musl
run: |
git submodule update --init lib/musl
- name: Restore LLVM source cache
uses: actions/cache/restore@v3
id: cache-llvm-source
with:
key: llvm-source-16-linux-nix-v1
path: |
llvm-project/compiler-rt
- name: Download LLVM source
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
run: make llvm-source
- name: Save LLVM source cache
uses: actions/cache/save@v3
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
with:
key: ${{ steps.cache-llvm-source.outputs.cache-primary-key }}
path: |
llvm-project/compiler-rt
- uses: cachix/install-nix-action@v22
- name: Test
run: |
nix develop --ignore-environment --keep HOME --command bash -c "go install && ~/go/bin/tinygo version && ~/go/bin/tinygo build -o test ./testdata/cgo"
+1 -1
View File
@@ -49,7 +49,7 @@ jobs:
path: | path: |
~/.cache/go-build ~/.cache/go-build
~/go/pkg/mod ~/go/pkg/mod
- run: make gen-device -j4 - run: make gen-device
- name: Download drivers repo - name: Download drivers repo
run: git clone https://github.com/tinygo-org/drivers.git run: git clone https://github.com/tinygo-org/drivers.git
- name: Save HEAD - name: Save HEAD
+3 -3
View File
@@ -96,9 +96,9 @@ jobs:
run: make wasi-libc run: make wasi-libc
- name: Install wasmtime - name: Install wasmtime
run: | run: |
scoop install wasmtime@14.0.4 scoop install wasmtime
- name: make gen-device - name: make gen-device
run: make -j3 gen-device run: make gen-device
- name: Test TinyGo - name: Test TinyGo
shell: bash shell: bash
run: make test GOTESTFLAGS="-short" run: make test GOTESTFLAGS="-short"
@@ -203,7 +203,7 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
shell: bash shell: bash
run: | run: |
scoop install binaryen && scoop install wasmtime@14.0.4 scoop install binaryen wasmtime
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v3
- name: Install Go - name: Install Go
+1 -1
View File
@@ -85,7 +85,7 @@ Now that we have a working static build, it's time to make a release tarball:
If you did not clone the repository with the `--recursive` option, you will get errors until you initialize the project submodules: If you did not clone the repository with the `--recursive` option, you will get errors until you initialize the project submodules:
git submodule update --init --recursive git submodule update --init
The release tarball is stored in build/release.tar.gz, and can be extracted with The release tarball is stored in build/release.tar.gz, and can be extracted with
the following command (for example in ~/lib): the following command (for example in ~/lib):
+10 -12
View File
@@ -10,7 +10,7 @@ LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
# Try to autodetect LLVM build tools. # Try to autodetect LLVM build tools.
# Versions are listed here in descending priority order. # Versions are listed here in descending priority order.
LLVM_VERSIONS = 17 16 15 LLVM_VERSIONS = 16 15
errifempty = $(if $(1),$(1),$(error $(2))) errifempty = $(if $(1),$(1),$(error $(2)))
detect = $(shell which $(call errifempty,$(firstword $(foreach p,$(2),$(shell command -v $(p) 2> /dev/null && echo $(p)))),failed to locate $(1) at any of: $(2))) detect = $(shell which $(call errifempty,$(firstword $(foreach p,$(2),$(shell command -v $(p) 2> /dev/null && echo $(p)))),failed to locate $(1) at any of: $(2)))
toolSearchPathsVersion = $(1)-$(2) toolSearchPathsVersion = $(1)-$(2)
@@ -32,6 +32,9 @@ export GOROOT = $(shell $(GO) env GOROOT)
# Flags to pass to go test. # Flags to pass to go test.
GOTESTFLAGS ?= GOTESTFLAGS ?=
# md5sum binary
MD5SUM = md5sum
# tinygo binary for tests # tinygo binary for tests
TINYGO ?= $(call detect,tinygo,tinygo $(CURDIR)/build/tinygo) TINYGO ?= $(call detect,tinygo,tinygo $(CURDIR)/build/tinygo)
@@ -127,14 +130,14 @@ ifeq ($(OS),Windows_NT)
USE_SYSTEM_BINARYEN ?= 1 USE_SYSTEM_BINARYEN ?= 1
else ifeq ($(shell uname -s),Darwin) else ifeq ($(shell uname -s),Darwin)
MD5SUM ?= md5 MD5SUM = md5
CGO_LDFLAGS += -lxar CGO_LDFLAGS += -lxar
USE_SYSTEM_BINARYEN ?= 1 USE_SYSTEM_BINARYEN ?= 1
else ifeq ($(shell uname -s),FreeBSD) else ifeq ($(shell uname -s),FreeBSD)
MD5SUM ?= md5 MD5SUM = md5
START_GROUP = -Wl,--start-group START_GROUP = -Wl,--start-group
END_GROUP = -Wl,--end-group END_GROUP = -Wl,--end-group
else else
@@ -142,9 +145,6 @@ else
END_GROUP = -Wl,--end-group END_GROUP = -Wl,--end-group
endif endif
# md5sum binary default, can be overridden by an environment variable
MD5SUM ?= md5sum
# Libraries that should be linked in for the statically linked Clang. # Libraries that should be linked in for the statically linked Clang.
CLANG_LIB_NAMES = clangAnalysis clangAST clangASTMatchers clangBasic clangCodeGen clangCrossTU clangDriver clangDynamicASTMatchers clangEdit clangExtractAPI clangFormat clangFrontend clangFrontendTool clangHandleCXX clangHandleLLVM clangIndex clangLex clangParse clangRewrite clangRewriteFrontend clangSema clangSerialization clangSupport clangTooling clangToolingASTDiff clangToolingCore clangToolingInclusions CLANG_LIB_NAMES = clangAnalysis clangAST clangASTMatchers clangBasic clangCodeGen clangCrossTU clangDriver clangDynamicASTMatchers clangEdit clangExtractAPI clangFormat clangFrontend clangFrontendTool clangHandleCXX clangHandleLLVM clangIndex clangLex clangParse clangRewrite clangRewriteFrontend clangSema clangSerialization clangSupport clangTooling clangToolingASTDiff clangToolingCore clangToolingInclusions
CLANG_LIBS = $(START_GROUP) $(addprefix -l,$(CLANG_LIB_NAMES)) $(END_GROUP) -lstdc++ CLANG_LIBS = $(START_GROUP) $(addprefix -l,$(CLANG_LIB_NAMES)) $(END_GROUP) -lstdc++
@@ -190,7 +190,7 @@ gen-device: gen-device-stm32
endif endif
gen-device-avr: gen-device-avr:
@if [ ! -e lib/avr/README.md ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init --recursive"; exit 1; fi @if [ ! -e lib/avr/README.md ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
$(GO) build -o ./build/gen-device-avr ./tools/gen-device-avr/ $(GO) build -o ./build/gen-device-avr ./tools/gen-device-avr/
./build/gen-device-avr lib/avr/packs/atmega src/device/avr/ ./build/gen-device-avr lib/avr/packs/atmega src/device/avr/
./build/gen-device-avr lib/avr/packs/tiny src/device/avr/ ./build/gen-device-avr lib/avr/packs/tiny src/device/avr/
@@ -264,8 +264,8 @@ endif
.PHONY: wasi-libc .PHONY: wasi-libc
wasi-libc: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a wasi-libc: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a
lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init --recursive"; exit 1; fi @if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
cd lib/wasi-libc && $(MAKE) -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC="$(CLANG)" AR=$(LLVM_AR) NM=$(LLVM_NM) cd lib/wasi-libc && $(MAKE) -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC=$(CLANG) AR=$(LLVM_AR) NM=$(LLVM_NM)
# Check for Node.js used during WASM tests. # 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-)))
@@ -506,8 +506,6 @@ smoketest:
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/watchdog $(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/watchdog
@$(MD5SUM) test.hex @$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/device-id
@$(MD5SUM) test.hex
# test simulated boards on play.tinygo.org # test simulated boards on play.tinygo.org
ifneq ($(WASM), 0) ifneq ($(WASM), 0)
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1 $(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
@@ -880,7 +878,7 @@ deb:
@mkdir -p build/release-deb/usr/local/lib @mkdir -p build/release-deb/usr/local/lib
cp -ar build/release/tinygo build/release-deb/usr/local/lib/tinygo cp -ar build/release/tinygo build/release-deb/usr/local/lib/tinygo
ln -sf ../lib/tinygo/bin/tinygo build/release-deb/usr/local/bin/tinygo ln -sf ../lib/tinygo/bin/tinygo build/release-deb/usr/local/bin/tinygo
fpm -f -s dir -t deb -n tinygo -a $(DEB_ARCH) -v $(shell grep "const version = " goenv/version.go | awk '{print $$NF}') -m '@tinygo-org' --description='TinyGo is a Go compiler for small places.' --license='BSD 3-Clause' --url=https://tinygo.org/ --deb-changelog CHANGELOG.md -p build/release.deb -C ./build/release-deb fpm -f -s dir -t deb -n tinygo -a $(DEB_ARCH) -v $(shell grep "const Version = " goenv/version.go | awk '{print $$NF}') -m '@tinygo-org' --description='TinyGo is a Go compiler for small places.' --license='BSD 3-Clause' --url=https://tinygo.org/ --deb-changelog CHANGELOG.md -p build/release.deb -C ./build/release-deb
ifneq ($(RELEASEONLY), 1) ifneq ($(RELEASEONLY), 1)
release: build/release release: build/release
+1 -1
View File
@@ -1,6 +1,6 @@
# TinyGo - Go compiler for small places # TinyGo - Go compiler for small places
[![Linux](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml) [![macOS](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml) [![Windows](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml) [![Docker](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml) [![Nix](https://github.com/tinygo-org/tinygo/actions/workflows/nix.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/nix.yml) [![CircleCI](https://circleci.com/gh/tinygo-org/tinygo/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/tinygo/tree/dev) [![Linux](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml) [![macOS](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml) [![Windows](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml) [![Docker](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml/badge.svg?branch=dev)](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml) [![CircleCI](https://circleci.com/gh/tinygo-org/tinygo/tree/dev.svg?style=svg)](https://circleci.com/gh/tinygo-org/tinygo/tree/dev)
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (wasm/wasi), and command-line tools. TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (wasm/wasi), and command-line tools.
+29 -31
View File
@@ -114,30 +114,6 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
cacheDir = tmpdir cacheDir = tmpdir
} }
// Create default global values.
globalValues := map[string]map[string]string{
"runtime": {
"buildVersion": goenv.Version(),
},
"testing": {},
}
if config.TestConfig.CompileTestBinary {
// The testing.testBinary is set to "1" when in a test.
// This is needed for testing.Testing() to work correctly.
globalValues["testing"]["testBinary"] = "1"
}
// Copy over explicitly set global values, like
// -ldflags="-X main.Version="1.0"
for pkgPath, vals := range config.Options.GlobalValues {
if _, ok := globalValues[pkgPath]; !ok {
globalValues[pkgPath] = map[string]string{}
}
for k, v := range vals {
globalValues[pkgPath][k] = v
}
}
// Check for a libc dependency. // Check for a libc dependency.
// As a side effect, this also creates the headers for the given libc, if // As a side effect, this also creates the headers for the given libc, if
// the libc needs them. // the libc needs them.
@@ -192,7 +168,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
CodeModel: config.CodeModel(), CodeModel: config.CodeModel(),
RelocationModel: config.RelocationModel(), RelocationModel: config.RelocationModel(),
SizeLevel: sizeLevel, SizeLevel: sizeLevel,
TinyGoVersion: goenv.Version(), TinyGoVersion: goenv.Version,
Scheduler: config.Scheduler(), Scheduler: config.Scheduler(),
AutomaticStackSize: config.AutomaticStackSize(), AutomaticStackSize: config.AutomaticStackSize(),
@@ -211,7 +187,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
defer machine.Dispose() defer machine.Dispose()
// Load entire program AST into memory. // Load entire program AST into memory.
lprogram, err := loader.Load(config, pkgName, types.Config{ lprogram, err := loader.Load(config, pkgName, config.ClangHeaders, types.Config{
Sizes: compiler.Sizes(machine), Sizes: compiler.Sizes(machine),
}) })
if err != nil { if err != nil {
@@ -240,12 +216,34 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
var packageJobs []*compileJob var packageJobs []*compileJob
packageActionIDJobs := make(map[string]*compileJob) packageActionIDJobs := make(map[string]*compileJob)
if config.Options.GlobalValues == nil {
config.Options.GlobalValues = make(map[string]map[string]string)
}
if config.Options.GlobalValues["runtime"]["buildVersion"] == "" {
version := goenv.Version
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
}
if config.Options.GlobalValues["runtime"] == nil {
config.Options.GlobalValues["runtime"] = make(map[string]string)
}
config.Options.GlobalValues["runtime"]["buildVersion"] = version
}
if config.TestConfig.CompileTestBinary {
// The testing.testBinary is set to "1" when in a test.
// This is needed for testing.Testing() to work correctly.
if config.Options.GlobalValues["testing"] == nil {
config.Options.GlobalValues["testing"] = make(map[string]string)
}
config.Options.GlobalValues["testing"]["testBinary"] = "1"
}
var embedFileObjects []*compileJob var embedFileObjects []*compileJob
for _, pkg := range lprogram.Sorted() { for _, pkg := range lprogram.Sorted() {
pkg := pkg // necessary to avoid a race condition pkg := pkg // necessary to avoid a race condition
var undefinedGlobals []string var undefinedGlobals []string
for name := range globalValues[pkg.Pkg.Path()] { for name := range config.Options.GlobalValues[pkg.Pkg.Path()] {
undefinedGlobals = append(undefinedGlobals, name) undefinedGlobals = append(undefinedGlobals, name)
} }
sort.Strings(undefinedGlobals) sort.Strings(undefinedGlobals)
@@ -573,7 +571,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
// Run all optimization passes, which are much more effective now // Run all optimization passes, which are much more effective now
// that the optimizer can see the whole program at once. // that the optimizer can see the whole program at once.
err := optimizeProgram(mod, config, globalValues) err := optimizeProgram(mod, config)
if err != nil { if err != nil {
return err return err
} }
@@ -662,7 +660,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
job := &compileJob{ job := &compileJob{
description: "compile extra file " + path, description: "compile extra file " + path,
run: func(job *compileJob) error { run: func(job *compileJob) error {
result, err := compileAndCacheCFile(abspath, tmpdir, config.CFlags(false), config.Options.PrintCommands) result, err := compileAndCacheCFile(abspath, tmpdir, config.CFlags(), config.Options.PrintCommands)
job.result = result job.result = result
return err return err
}, },
@@ -1042,7 +1040,7 @@ func createEmbedObjectFile(data, hexSum, sourceFile, sourceDir, tmpdir string, c
// optimizeProgram runs a series of optimizations and transformations that are // optimizeProgram runs a series of optimizations and transformations that are
// needed to convert a program to its final form. Some transformations are not // needed to convert a program to its final form. Some transformations are not
// optional and must be run as the compiler expects them to run. // optional and must be run as the compiler expects them to run.
func optimizeProgram(mod llvm.Module, config *compileopts.Config, globalValues map[string]map[string]string) error { func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA()) err := interp.Run(mod, config.Options.InterpTimeout, config.DumpSSA())
if err != nil { if err != nil {
return err return err
@@ -1061,7 +1059,7 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config, globalValues m
} }
// Insert values from -ldflags="-X ..." into the IR. // Insert values from -ldflags="-X ..." into the IR.
err = setGlobalValues(mod, globalValues) err = setGlobalValues(mod, config.Options.GlobalValues)
if err != nil { if err != nil {
return err return err
} }
+6 -3
View File
@@ -8,6 +8,7 @@ import (
"testing" "testing"
"github.com/tinygo-org/tinygo/compileopts" "github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
@@ -73,6 +74,7 @@ func TestClangAttributes(t *testing.T) {
func testClangAttributes(t *testing.T, options *compileopts.Options) { func testClangAttributes(t *testing.T, options *compileopts.Options) {
testDir := t.TempDir() testDir := t.TempDir()
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
ctx := llvm.NewContext() ctx := llvm.NewContext()
defer ctx.Dispose() defer ctx.Dispose()
@@ -82,8 +84,9 @@ func testClangAttributes(t *testing.T, options *compileopts.Options) {
t.Fatalf("could not load target: %s", err) t.Fatalf("could not load target: %s", err)
} }
config := compileopts.Config{ config := compileopts.Config{
Options: options, Options: options,
Target: target, Target: target,
ClangHeaders: clangHeaderPath,
} }
// Create a very simple C input file. // Create a very simple C input file.
@@ -95,7 +98,7 @@ func testClangAttributes(t *testing.T, options *compileopts.Options) {
// Compile this file using Clang. // Compile this file using Clang.
outpath := filepath.Join(testDir, "test.bc") outpath := filepath.Join(testDir, "test.bc")
flags := append([]string{"-c", "-emit-llvm", "-o", outpath, srcpath}, config.CFlags(false)...) flags := append([]string{"-c", "-emit-llvm", "-o", outpath, srcpath}, config.CFlags()...)
if config.GOOS() == "darwin" { if config.GOOS() == "darwin" {
// Silence some warnings that happen when testing GOOS=darwin on // Silence some warnings that happen when testing GOOS=darwin on
// something other than MacOS. // something other than MacOS.
+10 -34
View File
@@ -77,15 +77,6 @@ func ReadBuildID() ([]byte, error) {
} }
return raw[4:], nil return raw[4:], nil
} }
// Normally we would have found a build ID by now. But not on Nix,
// unfortunately, because Nix adds -no_uuid for some reason:
// https://github.com/NixOS/nixpkgs/issues/178366
// Fall back to the same implementation that we use for Windows.
id, err := readRawGoBuildID(f, 32*1024)
if len(id) != 0 || err != nil {
return id, err
}
default: default:
// On other platforms (such as Windows) there isn't such a convenient // On other platforms (such as Windows) there isn't such a convenient
// build ID. Luckily, Go does have an equivalent of the build ID, which // build ID. Luckily, Go does have an equivalent of the build ID, which
@@ -97,31 +88,16 @@ func ReadBuildID() ([]byte, error) {
// directly. Luckily the build ID is always at the start of the file. // directly. Luckily the build ID is always at the start of the file.
// For details, see: // For details, see:
// https://github.com/golang/go/blob/master/src/cmd/internal/buildid/buildid.go // https://github.com/golang/go/blob/master/src/cmd/internal/buildid/buildid.go
id, err := readRawGoBuildID(f, 4096) fileStart := make([]byte, 4096)
if len(id) != 0 || err != nil { _, err := io.ReadFull(f, fileStart)
return id, err index := bytes.Index(fileStart, []byte("\xff Go build ID: \""))
if index < 0 || index > len(fileStart)-103 {
return nil, fmt.Errorf("could not find build id in %s", err)
}
buf := fileStart[index : index+103]
if bytes.HasPrefix(buf, []byte("\xff Go build ID: \"")) && bytes.HasSuffix(buf, []byte("\"\n \xff")) {
return buf[len("\xff Go build ID: \"") : len(buf)-1], nil
} }
} }
return nil, fmt.Errorf("could not find build ID in %v", executable) return nil, fmt.Errorf("could not find build ID in %s", executable)
}
// The Go toolchain stores a build ID in the binary that we can use, as a
// fallback if binary file specific build IDs can't be obtained.
// This function reads that build ID from the binary.
func readRawGoBuildID(f *os.File, prefixSize int) ([]byte, error) {
fileStart := make([]byte, prefixSize)
_, err := io.ReadFull(f, fileStart)
if err != nil {
return nil, fmt.Errorf("could not read build id from %s: %v", f.Name(), err)
}
index := bytes.Index(fileStart, []byte("\xff Go build ID: \""))
if index < 0 || index > len(fileStart)-103 {
return nil, fmt.Errorf("could not find build id in %s", f.Name())
}
buf := fileStart[index : index+103]
if bytes.HasPrefix(buf, []byte("\xff Go build ID: \"")) && bytes.HasSuffix(buf, []byte("\"\n \xff")) {
return buf[len("\xff Go build ID: \"") : len(buf)-1], nil
}
return nil, nil
} }
+3
View File
@@ -33,10 +33,13 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
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.21, got go%d.%d", major, minor)
} }
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
return &compileopts.Config{ return &compileopts.Config{
Options: options, Options: options,
Target: spec, Target: spec,
GoMinorVersion: minor, GoMinorVersion: minor,
ClangHeaders: clangHeaderPath,
TestConfig: options.TestConfig, TestConfig: options.TestConfig,
}, nil }, nil
} }
+105
View File
@@ -0,0 +1,105 @@
package builder
import (
"errors"
"io/fs"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"sort"
"strings"
"tinygo.org/x/go-llvm"
)
// getClangHeaderPath returns the path to the built-in Clang headers. It tries
// multiple locations, which should make it find the directory when installed in
// various ways.
func getClangHeaderPath(TINYGOROOT string) string {
// Check whether we're running from the source directory.
path := filepath.Join(TINYGOROOT, "llvm-project", "clang", "lib", "Headers")
if _, err := os.Stat(path); !errors.Is(err, fs.ErrNotExist) {
return path
}
// Check whether we're running from the installation directory.
path = filepath.Join(TINYGOROOT, "lib", "clang", "include")
if _, err := os.Stat(path); !errors.Is(err, fs.ErrNotExist) {
return path
}
// It looks like we are built with a system-installed LLVM. Do a last
// attempt: try to use Clang headers relative to the clang binary.
llvmMajor := strings.Split(llvm.Version, ".")[0]
for _, cmdName := range commands["clang"] {
binpath, err := exec.LookPath(cmdName)
if err == nil {
// This should be the command that will also be used by
// execCommand. To avoid inconsistencies, make sure we use the
// headers relative to this command.
binpath, err = filepath.EvalSymlinks(binpath)
if err != nil {
// Unexpected.
return ""
}
// Example executable:
// /usr/lib/llvm-9/bin/clang
// Example include path:
// /usr/lib/llvm-9/lib64/clang/9.0.1/include/
llvmRoot := filepath.Dir(filepath.Dir(binpath))
clangVersionRoot := filepath.Join(llvmRoot, "lib64", "clang")
dirs64, err64 := ioutil.ReadDir(clangVersionRoot)
// Example include path:
// /usr/lib/llvm-9/lib/clang/9.0.1/include/
clangVersionRoot = filepath.Join(llvmRoot, "lib", "clang")
dirs32, err32 := ioutil.ReadDir(clangVersionRoot)
if err64 != nil && err32 != nil {
// Unexpected.
continue
}
dirnames := make([]string, len(dirs64)+len(dirs32))
dirCount := 0
for _, d := range dirs32 {
name := d.Name()
if name == llvmMajor || strings.HasPrefix(name, llvmMajor+".") {
dirnames[dirCount] = filepath.Join(llvmRoot, "lib", "clang", name)
dirCount++
}
}
for _, d := range dirs64 {
name := d.Name()
if name == llvmMajor || strings.HasPrefix(name, llvmMajor+".") {
dirnames[dirCount] = filepath.Join(llvmRoot, "lib64", "clang", name)
dirCount++
}
}
sort.Strings(dirnames)
// Check for the highest version first.
for i := dirCount - 1; i >= 0; i-- {
path := filepath.Join(dirnames[i], "include")
_, err := os.Stat(filepath.Join(path, "stdint.h"))
if err == nil {
return path
}
}
}
}
// On Arch Linux, the clang executable is stored in /usr/bin rather than being symlinked from there.
// Search directly in /usr/lib for clang.
if matches, err := filepath.Glob("/usr/lib/clang/" + llvmMajor + ".*.*"); err == nil {
// Check for the highest version first.
sort.Strings(matches)
for i := len(matches) - 1; i >= 0; i-- {
path := filepath.Join(matches[i], "include")
_, err := os.Stat(filepath.Join(path, "stdint.h"))
if err == nil {
return path
}
}
}
// Could not find it.
return ""
}
-4
View File
@@ -143,10 +143,6 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
// reproducible. Otherwise the temporary directory is stored in the archive // reproducible. Otherwise the temporary directory is stored in the archive
// itself, which varies each run. // itself, which varies each run.
args := append(l.cflags(target, headerPath), "-c", "-Oz", "-gdwarf-4", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir) args := append(l.cflags(target, headerPath), "-c", "-Oz", "-gdwarf-4", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir)
resourceDir := goenv.ClangResourceDir(false)
if resourceDir != "" {
args = append(args, "-resource-dir="+resourceDir)
}
cpu := config.CPU() cpu := config.CPU()
if cpu != "" { if cpu != "" {
// X86 has deprecated the -mcpu flag, so we need to use -march instead. // X86 has deprecated the -mcpu flag, so we need to use -march instead.
+79 -93
View File
@@ -3,7 +3,6 @@ package builder
import ( import (
"os" "os"
"path/filepath" "path/filepath"
"strings"
"github.com/tinygo-org/tinygo/goenv" "github.com/tinygo-org/tinygo/goenv"
) )
@@ -42,23 +41,91 @@ var Picolibc = Library{
}, },
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") }, sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") },
librarySources: func(target string) ([]string, error) { librarySources: func(target string) ([]string, error) {
sources := append([]string(nil), picolibcSources...) return picolibcSources, nil
if !strings.HasPrefix(target, "avr") {
// Small chips without long jumps can't compile many files (printf,
// pow, etc). Therefore exclude those source files for those chips.
// Unfortunately it's difficult to exclude only some chips, so this
// excludes those files on all AVR chips for now.
// More information:
// https://github.com/llvm/llvm-project/issues/67042
sources = append(sources, picolibcSourcesLarge...)
}
return sources, nil
}, },
} }
var picolibcSources = []string{ var picolibcSources = []string{
"../../picolibc-stdio.c", "../../picolibc-stdio.c",
// srcs_tinystdio
"libc/tinystdio/asprintf.c",
"libc/tinystdio/bufio.c",
"libc/tinystdio/clearerr.c",
"libc/tinystdio/ecvt_r.c",
"libc/tinystdio/ecvt.c",
"libc/tinystdio/ecvtf_r.c",
"libc/tinystdio/ecvtf.c",
"libc/tinystdio/fcvt.c",
"libc/tinystdio/fcvt_r.c",
"libc/tinystdio/fcvtf.c",
"libc/tinystdio/fcvtf_r.c",
"libc/tinystdio/gcvt.c",
"libc/tinystdio/gcvtf.c",
"libc/tinystdio/fclose.c",
"libc/tinystdio/fdevopen.c",
"libc/tinystdio/feof.c",
"libc/tinystdio/ferror.c",
"libc/tinystdio/fflush.c",
"libc/tinystdio/fgetc.c",
"libc/tinystdio/fgets.c",
"libc/tinystdio/fileno.c",
"libc/tinystdio/filestrget.c",
"libc/tinystdio/filestrput.c",
"libc/tinystdio/filestrputalloc.c",
"libc/tinystdio/fmemopen.c",
"libc/tinystdio/fprintf.c",
"libc/tinystdio/fputc.c",
"libc/tinystdio/fputs.c",
"libc/tinystdio/fread.c",
//"libc/tinystdio/freopen.c", // crashes with AVR, see: https://github.com/picolibc/picolibc/pull/369
"libc/tinystdio/fscanf.c",
"libc/tinystdio/fseek.c",
"libc/tinystdio/fseeko.c",
"libc/tinystdio/ftell.c",
"libc/tinystdio/ftello.c",
"libc/tinystdio/fwrite.c",
"libc/tinystdio/getchar.c",
"libc/tinystdio/gets.c",
"libc/tinystdio/matchcaseprefix.c",
"libc/tinystdio/mktemp.c",
"libc/tinystdio/perror.c",
"libc/tinystdio/printf.c",
"libc/tinystdio/putchar.c",
"libc/tinystdio/puts.c",
"libc/tinystdio/rewind.c",
"libc/tinystdio/scanf.c",
"libc/tinystdio/setbuf.c",
"libc/tinystdio/setbuffer.c",
"libc/tinystdio/setlinebuf.c",
"libc/tinystdio/setvbuf.c",
"libc/tinystdio/snprintf.c",
"libc/tinystdio/sprintf.c",
"libc/tinystdio/snprintfd.c",
"libc/tinystdio/snprintff.c",
"libc/tinystdio/sprintff.c",
"libc/tinystdio/sprintfd.c",
"libc/tinystdio/sscanf.c",
"libc/tinystdio/strfromf.c",
"libc/tinystdio/strfromd.c",
"libc/tinystdio/strtof.c",
"libc/tinystdio/strtof_l.c",
"libc/tinystdio/strtod.c",
"libc/tinystdio/strtod_l.c",
"libc/tinystdio/ungetc.c",
"libc/tinystdio/vasprintf.c",
"libc/tinystdio/vfiprintf.c",
"libc/tinystdio/vfprintf.c",
"libc/tinystdio/vfprintff.c",
"libc/tinystdio/vfscanf.c",
"libc/tinystdio/vfiscanf.c",
"libc/tinystdio/vfscanff.c",
"libc/tinystdio/vprintf.c",
"libc/tinystdio/vscanf.c",
"libc/tinystdio/vsscanf.c",
"libc/tinystdio/vsnprintf.c",
"libc/tinystdio/vsprintf.c",
"libc/string/bcmp.c", "libc/string/bcmp.c",
"libc/string/bcopy.c", "libc/string/bcopy.c",
"libc/string/bzero.c", "libc/string/bzero.c",
@@ -162,87 +229,6 @@ var picolibcSources = []string{
"libc/string/wmempcpy.c", "libc/string/wmempcpy.c",
"libc/string/wmemset.c", "libc/string/wmemset.c",
"libc/string/xpg_strerror_r.c", "libc/string/xpg_strerror_r.c",
}
// Parts of picolibc that are too large for small AVRs.
var picolibcSourcesLarge = []string{
// srcs_tinystdio
"libc/tinystdio/asprintf.c",
"libc/tinystdio/bufio.c",
"libc/tinystdio/clearerr.c",
"libc/tinystdio/ecvt_r.c",
"libc/tinystdio/ecvt.c",
"libc/tinystdio/ecvtf_r.c",
"libc/tinystdio/ecvtf.c",
"libc/tinystdio/fcvt.c",
"libc/tinystdio/fcvt_r.c",
"libc/tinystdio/fcvtf.c",
"libc/tinystdio/fcvtf_r.c",
"libc/tinystdio/gcvt.c",
"libc/tinystdio/gcvtf.c",
"libc/tinystdio/fclose.c",
"libc/tinystdio/fdevopen.c",
"libc/tinystdio/feof.c",
"libc/tinystdio/ferror.c",
"libc/tinystdio/fflush.c",
"libc/tinystdio/fgetc.c",
"libc/tinystdio/fgets.c",
"libc/tinystdio/fileno.c",
"libc/tinystdio/filestrget.c",
"libc/tinystdio/filestrput.c",
"libc/tinystdio/filestrputalloc.c",
"libc/tinystdio/fmemopen.c",
"libc/tinystdio/fprintf.c",
"libc/tinystdio/fputc.c",
"libc/tinystdio/fputs.c",
"libc/tinystdio/fread.c",
//"libc/tinystdio/freopen.c", // crashes with AVR, see: https://github.com/picolibc/picolibc/pull/369
"libc/tinystdio/fscanf.c",
"libc/tinystdio/fseek.c",
"libc/tinystdio/fseeko.c",
"libc/tinystdio/ftell.c",
"libc/tinystdio/ftello.c",
"libc/tinystdio/fwrite.c",
"libc/tinystdio/getchar.c",
"libc/tinystdio/gets.c",
"libc/tinystdio/matchcaseprefix.c",
"libc/tinystdio/mktemp.c",
"libc/tinystdio/perror.c",
"libc/tinystdio/printf.c",
"libc/tinystdio/putchar.c",
"libc/tinystdio/puts.c",
"libc/tinystdio/rewind.c",
"libc/tinystdio/scanf.c",
"libc/tinystdio/setbuf.c",
"libc/tinystdio/setbuffer.c",
"libc/tinystdio/setlinebuf.c",
"libc/tinystdio/setvbuf.c",
"libc/tinystdio/snprintf.c",
"libc/tinystdio/sprintf.c",
"libc/tinystdio/snprintfd.c",
"libc/tinystdio/snprintff.c",
"libc/tinystdio/sprintff.c",
"libc/tinystdio/sprintfd.c",
"libc/tinystdio/sscanf.c",
"libc/tinystdio/strfromf.c",
"libc/tinystdio/strfromd.c",
"libc/tinystdio/strtof.c",
"libc/tinystdio/strtof_l.c",
"libc/tinystdio/strtod.c",
"libc/tinystdio/strtod_l.c",
"libc/tinystdio/ungetc.c",
"libc/tinystdio/vasprintf.c",
"libc/tinystdio/vfiprintf.c",
"libc/tinystdio/vfprintf.c",
"libc/tinystdio/vfprintff.c",
"libc/tinystdio/vfscanf.c",
"libc/tinystdio/vfiscanf.c",
"libc/tinystdio/vfscanff.c",
"libc/tinystdio/vprintf.c",
"libc/tinystdio/vscanf.c",
"libc/tinystdio/vsscanf.c",
"libc/tinystdio/vsnprintf.c",
"libc/tinystdio/vsprintf.c",
"libm/common/sf_finite.c", "libm/common/sf_finite.c",
"libm/common/sf_copysign.c", "libm/common/sf_copysign.c",
+6
View File
@@ -1,6 +1,7 @@
package builder package builder
import ( import (
"errors"
"os" "os"
"os/exec" "os/exec"
@@ -11,6 +12,11 @@ import (
func runCCompiler(flags ...string) error { func runCCompiler(flags ...string) error {
if hasBuiltinTools { if hasBuiltinTools {
// Compile this with the internal Clang compiler. // Compile this with the internal Clang compiler.
headerPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
if headerPath == "" {
return errors.New("could not locate Clang headers")
}
flags = append(flags, "-I"+headerPath)
cmd := exec.Command(os.Args[0], append([]string{"clang"}, flags...)...) cmd := exec.Command(os.Args[0], append([]string{"clang"}, flags...)...)
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
+4 -1
View File
@@ -165,7 +165,7 @@ 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, clangHeaders string) (*ast.File, []string, []string, []string, map[string][]byte, []error) {
p := &cgoPackage{ p := &cgoPackage{
currentDir: dir, currentDir: dir,
importPath: importPath, importPath: importPath,
@@ -292,6 +292,9 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
// have better alternatives anyway. // have better alternatives anyway.
cflagsForCGo := append([]string{"-D_FORTIFY_SOURCE=0"}, cflags...) cflagsForCGo := append([]string{"-D_FORTIFY_SOURCE=0"}, cflags...)
cflagsForCGo = append(cflagsForCGo, p.cflags...) cflagsForCGo = append(cflagsForCGo, p.cflags...)
if clangHeaders != "" {
cflagsForCGo = append(cflagsForCGo, "-isystem", clangHeaders)
}
// Retrieve types such as C.int, C.longlong, etc from C. // Retrieve types such as C.int, C.longlong, etc from C.
p.newCGoFile(nil, -1).readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) { p.newCGoFile(nil, -1).readNames(builtinAliasTypedefs, cflagsForCGo, "", func(names map[string]clangCursor) {
+1 -1
View File
@@ -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) cgoAST, _, _, _, _, 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
+2 -2
View File
@@ -8,8 +8,8 @@ package cgo
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@15/include #cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@15/include
#cgo freebsd CFLAGS: -I/usr/local/llvm15/include #cgo freebsd CFLAGS: -I/usr/local/llvm15/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-15/lib -lclang #cgo linux LDFLAGS: -L/usr/lib/llvm-15/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@15/lib -lclang #cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@15/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@15/lib -lclang #cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@15/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm15/lib -lclang #cgo freebsd LDFLAGS: -L/usr/local/llvm15/lib -lclang
*/ */
import "C" import "C"
+4 -4
View File
@@ -1,8 +1,8 @@
//go:build !byollvm && !llvm15 && !llvm17 //go:build !byollvm && !llvm15
package cgo package cgo
// As of 2023-05-05, there is a packaging issue with LLVM 16 on Debian: // As of 2023-05-05, there is a packaging issue on Debian:
// https://github.com/llvm/llvm-project/issues/62199 // https://github.com/llvm/llvm-project/issues/62199
// A workaround is to fix this locally, using something like this: // A workaround is to fix this locally, using something like this:
// //
@@ -14,8 +14,8 @@ package cgo
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@16/include #cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@16/include
#cgo freebsd CFLAGS: -I/usr/local/llvm16/include #cgo freebsd CFLAGS: -I/usr/local/llvm16/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-16/lib -lclang #cgo linux LDFLAGS: -L/usr/lib/llvm-16/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@16/lib -lclang #cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@16/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@16/lib -lclang #cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@16/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm16/lib -lclang #cgo freebsd LDFLAGS: -L/usr/local/llvm16/lib -lclang
*/ */
import "C" import "C"
-15
View File
@@ -1,15 +0,0 @@
//go:build !byollvm && llvm17
package cgo
/*
#cgo linux CFLAGS: -I/usr/include/llvm-17 -I/usr/include/llvm-c-17 -I/usr/lib/llvm-17/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@17/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@17/include
#cgo freebsd CFLAGS: -I/usr/local/llvm17/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-17/lib -lclang
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@17/lib -lclang
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@17/lib -lclang
#cgo freebsd LDFLAGS: -L/usr/local/llvm17/lib -lclang
*/
import "C"
+6 -21
View File
@@ -19,6 +19,7 @@ type Config struct {
Options *Options Options *Options
Target *TargetSpec Target *TargetSpec
GoMinorVersion int GoMinorVersion int
ClangHeaders string // Clang built-in header include path
TestConfig TestConfig TestConfig TestConfig
} }
@@ -258,39 +259,24 @@ func (c *Config) DefaultBinaryExtension() string {
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo // CFlags returns the flags to pass to the C compiler. This is necessary for CGo
// preprocessing. // preprocessing.
func (c *Config) CFlags(libclang bool) []string { func (c *Config) CFlags() []string {
var cflags []string var cflags []string
for _, flag := range c.Target.CFlags { for _, flag := range c.Target.CFlags {
cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT"))) cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT")))
} }
resourceDir := goenv.ClangResourceDir(libclang)
if resourceDir != "" {
// The resource directory contains the built-in clang headers like
// stdbool.h, stdint.h, float.h, etc.
// It is left empty if we're using an external compiler (that already
// knows these headers).
cflags = append(cflags,
"-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":
root := goenv.Get("TINYGOROOT") root := goenv.Get("TINYGOROOT")
cflags = append(cflags, cflags = append(cflags,
"-nostdlibinc", "--sysroot="+filepath.Join(root, "lib/macos-minimal-sdk/src"),
"-isystem", filepath.Join(root, "lib/macos-minimal-sdk/src/usr/include"),
) )
case "picolibc": case "picolibc":
root := goenv.Get("TINYGOROOT") root := goenv.Get("TINYGOROOT")
picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc") picolibcDir := filepath.Join(root, "lib", "picolibc", "newlib", "libc")
path, _ := c.LibcPath("picolibc") path, _ := c.LibcPath("picolibc")
cflags = append(cflags, cflags = append(cflags,
"-nostdlibinc", "--sysroot="+path,
"-isystem", filepath.Join(path, "include"), "-isystem", filepath.Join(path, "include"), // necessary for Xtensa
"-isystem", filepath.Join(picolibcDir, "include"), "-isystem", filepath.Join(picolibcDir, "include"),
"-isystem", filepath.Join(picolibcDir, "tinystdio"), "-isystem", filepath.Join(picolibcDir, "tinystdio"),
) )
@@ -311,8 +297,7 @@ func (c *Config) CFlags(libclang bool) []string {
root := goenv.Get("TINYGOROOT") root := goenv.Get("TINYGOROOT")
path, _ := c.LibcPath("mingw-w64") path, _ := c.LibcPath("mingw-w64")
cflags = append(cflags, cflags = append(cflags,
"-nostdlibinc", "--sysroot="+path,
"-isystem", filepath.Join(path, "include"),
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"), "-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "crt"),
"-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"), "-isystem", filepath.Join(root, "lib", "mingw-w64", "mingw-w64-headers", "defaults", "include"),
"-D_UCRT", "-D_UCRT",
+2 -39
View File
@@ -246,43 +246,6 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
return spec, nil return spec, nil
} }
// GetTargetSpecs retrieves target specifications from the TINYGOROOT targets
// directory. Only valid target JSON files are considered, and the function
// returns a map of target names to their respective TargetSpec.
func GetTargetSpecs() (map[string]*TargetSpec, error) {
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
entries, err := os.ReadDir(dir)
if err != nil {
return nil, fmt.Errorf("could not list targets: %w", err)
}
maps := map[string]*TargetSpec{}
for _, entry := range entries {
entryInfo, err := entry.Info()
if err != nil {
return nil, fmt.Errorf("could not get entry info: %w", err)
}
if !entryInfo.Mode().IsRegular() || !strings.HasSuffix(entry.Name(), ".json") {
// Only inspect JSON files.
continue
}
path := filepath.Join(dir, entry.Name())
spec, err := LoadTarget(&Options{Target: path})
if err != nil {
return nil, fmt.Errorf("could not list target: %w", err)
}
if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" {
// This doesn't look like a regular target file, but rather like
// a parent target (such as targets/cortex-m.json).
continue
}
name := entry.Name()
name = name[:len(name)-5]
maps[name] = spec
}
return maps, nil
}
func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) { func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
// No target spec available. Use the default one, useful on most systems // No target spec available. Use the default one, useful on most systems
// with a regular OS. // with a regular OS.
@@ -381,12 +344,12 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
spec.Linker = "wasm-ld" spec.Linker = "wasm-ld"
spec.RTLib = "compiler-rt" spec.RTLib = "compiler-rt"
spec.Libc = "wasi-libc" spec.Libc = "wasi-libc"
spec.DefaultStackSize = 1024 * 64 // 64kB spec.DefaultStackSize = 1024 * 32 // 32kB
spec.LDFlags = append(spec.LDFlags, spec.LDFlags = append(spec.LDFlags,
"--stack-first", "--stack-first",
"--no-demangle", "--no-demangle",
) )
spec.Emulator = "wasmtime --dir={tmpDir}::/tmp {}" spec.Emulator = "wasmtime --mapdir=/tmp::{tmpDir} {}"
spec.ExtraFiles = append(spec.ExtraFiles, spec.ExtraFiles = append(spec.ExtraFiles,
"src/runtime/asm_tinygowasm.S", "src/runtime/asm_tinygowasm.S",
"src/internal/task/task_asyncify_wasm.S", "src/internal/task/task_asyncify_wasm.S",
+1 -1
View File
@@ -243,7 +243,7 @@ func testCompilePackage(t *testing.T, options *compileopts.Options, file string)
defer machine.Dispose() defer machine.Dispose()
// Load entire program AST into memory. // Load entire program AST into memory.
lprogram, err := loader.Load(config, "./testdata/"+file, types.Config{ lprogram, err := loader.Load(config, "./testdata/"+file, config.ClangHeaders, types.Config{
Sizes: Sizes(machine), Sizes: Sizes(machine),
}) })
if err != nil { if err != nil {
+5 -5
View File
@@ -21,7 +21,7 @@ entry:
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 { define hidden void @main.regularFunctionGoroutine(ptr %context) unnamed_addr #2 {
entry: entry:
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @"main.regularFunction$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 32768, ptr undef) #9
ret void ret void
} }
@@ -43,7 +43,7 @@ declare void @"internal/task.start"(i32, ptr, i32, ptr) #1
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 { define hidden void @main.inlineFunctionGoroutine(ptr %context) unnamed_addr #2 {
entry: entry:
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 65536, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @"main.inlineFunctionGoroutine$1$gowrapper" to i32), ptr nonnull inttoptr (i32 5 to ptr), i32 32768, ptr undef) #9
ret void ret void
} }
@@ -76,7 +76,7 @@ entry:
store i32 5, ptr %0, align 4 store i32 5, ptr %0, align 4
%1 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1 %1 = getelementptr inbounds { i32, ptr }, ptr %0, i32 0, i32 1
store ptr %n, ptr %1, align 4 store ptr %n, ptr %1, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @"main.closureFunctionGoroutine$1$gowrapper" to i32), ptr nonnull %0, i32 32768, ptr undef) #9
%2 = load i32, ptr %n, align 4 %2 = load i32, ptr %n, align 4
call void @runtime.printint32(i32 %2, ptr undef) #9 call void @runtime.printint32(i32 %2, ptr undef) #9
ret void ret void
@@ -113,7 +113,7 @@ entry:
store ptr %fn.context, ptr %1, align 4 store ptr %fn.context, ptr %1, align 4
%2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2 %2 = getelementptr inbounds { i32, ptr, ptr }, ptr %0, i32 0, i32 2
store ptr %fn.funcptr, ptr %2, align 4 store ptr %fn.funcptr, ptr %2, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 65536, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @main.funcGoroutine.gowrapper to i32), ptr nonnull %0, i32 32768, ptr undef) #9
ret void ret void
} }
@@ -167,7 +167,7 @@ entry:
store i32 4, ptr %.repack1, align 4 store i32 4, ptr %.repack1, align 4
%2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2 %2 = getelementptr inbounds { ptr, %runtime._string, ptr }, ptr %0, i32 0, i32 2
store ptr %itf.typecode, ptr %2, align 4 store ptr %itf.typecode, ptr %2, align 4
call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 65536, ptr undef) #9 call void @"internal/task.start"(i32 ptrtoint (ptr @"interface:{Print:func:{basic:string}{}}.Print$invoke$gowrapper" to i32), ptr nonnull %0, i32 32768, ptr undef) #9
ret void ret void
} }
Generated
-60
View File
@@ -1,60 +0,0 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1694529238,
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1696983906,
"narHash": "sha256-L7GyeErguS7Pg4h8nK0wGlcUTbfUMDu+HMf1UcyP72k=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "bd1cde45c77891214131cbbea5b1203e485a9d51",
"type": "github"
},
"original": {
"id": "nixpkgs",
"ref": "nixos-23.05",
"type": "indirect"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",
"version": 7
}
-85
View File
@@ -1,85 +0,0 @@
# A Nix flake file, mainly intended for developing TinyGo.
# You can download Nix here, for use on your Linux or macOS system:
# https://nixos.org/download.html
# After you have installed Nix, you can enter the development environment as
# follows:
#
# nix develop
#
# This drops you into a bash shell, where you can install TinyGo simply using
# the following command:
#
# go install
#
# That's all! Assuming you've set up your $PATH correctly, you can now use the
# tinygo command as usual:
#
# tinygo version
#
# But you'll need a bit more to make TinyGo actually able to compile code:
#
# make llvm-source # fetch compiler-rt
# git submodule update --init --recursive # fetch lots of other libraries and SVD files
# make gen-device -j4 # build src/device/*/*.go files
# make wasi-libc # build support for wasi/wasm
#
# With this, you should have an environment that can compile anything - except
# for the Xtensa architecture (ESP8266/ESP32) because support for that lives in
# a separate LLVM fork.
#
# You can also do many other things from this environment. Building and flashing
# should work as you're used to: it's not a VM or container so there are no
# access restrictions and you're running in the same host environment - just
# with a slightly different set of tools available.
{
inputs = {
# Use a recent stable release, but fix the version to make it reproducible.
# This version should be updated from time to time.
nixpkgs.url = "nixpkgs/nixos-23.05";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
in
with pkgs;
{
devShells.default = mkShell {
buildInputs = [
# These dependencies are required for building tinygo (go install).
go
llvmPackages_16.llvm
llvmPackages_16.libclang
# Additional dependencies needed at runtime, for building and/or
# flashing.
llvmPackages_16.lld
avrdude
binaryen
# Additional dependencies needed for on-chip debugging.
# These tools are rather big (especially GDB) and not frequently
# used, so are commented out. On-chip debugging is still possible if
# these tools are available in the host environment.
#gdb
#openocd
];
shellHook= ''
# Configure CLANG, LLVM_AR, and LLVM_NM for `make wasi-libc`.
# Without setting these explicitly, Homebrew versions might be used
# or the default `ar` and `nm` tools might be used (which don't
# support wasi).
export CLANG="clang-16 -resource-dir ${llvmPackages_16.clang.cc.lib}/lib/clang/16"
export LLVM_AR=llvm-ar
export LLVM_NM=llvm-nm
# Make `make smoketest` work (the default is `md5`, while Nix only
# has `md5sum`).
export MD5SUM=md5sum
# 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"\"
'';
};
}
);
}
+1 -1
View File
@@ -18,7 +18,7 @@ require (
golang.org/x/sys v0.11.0 golang.org/x/sys v0.11.0
golang.org/x/tools v0.12.0 golang.org/x/tools v0.12.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-20230920233244-32ed56c6be9c
) )
require ( require (
+2 -2
View File
@@ -65,5 +65,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
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-20230920233244-32ed56c6be9c h1:rS8mAFqf0CfxPCbtfsI3bWL4jkb0TBYA1wx7tY1nu28=
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-20230920233244-32ed56c6be9c/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
-103
View File
@@ -14,8 +14,6 @@ import (
"runtime" "runtime"
"strings" "strings"
"sync" "sync"
"tinygo.org/x/go-llvm"
) )
// Keys is a slice of all available environment variable keys. // Keys is a slice of all available environment variable keys.
@@ -35,20 +33,11 @@ func init() {
} }
} }
// Set to true if we're linking statically against LLVM.
var hasBuiltinTools = false
// TINYGOROOT is the path to the final location for checking tinygo files. If // TINYGOROOT is the path to the final location for checking tinygo files. If
// unset (by a -X ldflag), then sourceDir() will fallback to the original build // unset (by a -X ldflag), then sourceDir() will fallback to the original build
// directory. // directory.
var TINYGOROOT string var TINYGOROOT string
// If a particular Clang resource dir must always be used and TinyGo can't
// figure out the directory using heuristics, this global can be set using a
// linker flag.
// This is needed for Nix.
var clangResourceDir string
// Variables read from a `go env` command invocation. // Variables read from a `go env` command invocation.
var goEnvVars struct { var goEnvVars struct {
GOPATH string GOPATH string
@@ -295,95 +284,3 @@ func isSourceDir(root string) bool {
_, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go")) _, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go"))
return err == nil return err == nil
} }
// ClangResourceDir returns the clang resource dir if available. This is the
// -resource-dir flag. If it isn't available, an empty string is returned and
// -resource-dir should be left unset.
// The libclang flag must be set if the resource dir is read for use by
// libclang.
// In that case, the resource dir is always returned (even when linking
// dynamically against LLVM) because libclang always needs this directory.
func ClangResourceDir(libclang bool) string {
if clangResourceDir != "" {
// The resource dir is forced to a particular value at build time.
// This is needed on Nix for example, where Clang and libclang don't
// know their own resource dir.
// Also see:
// https://discourse.nixos.org/t/why-is-the-clang-resource-dir-split-in-a-separate-package/34114
return clangResourceDir
}
if !hasBuiltinTools && !libclang {
// Using external tools, so the resource dir doesn't need to be
// specified. Clang knows where to find it.
return ""
}
// Check whether we're running from a TinyGo release directory.
// This is the case for release binaries on GitHub.
root := Get("TINYGOROOT")
releaseHeaderDir := filepath.Join(root, "lib", "clang")
if _, err := os.Stat(releaseHeaderDir); !errors.Is(err, fs.ErrNotExist) {
return releaseHeaderDir
}
if hasBuiltinTools {
// We are statically linked to LLVM.
// Check whether we're running from the source directory.
// This typically happens when TinyGo was built using `make` as part of
// development.
llvmMajor := strings.Split(llvm.Version, ".")[0]
buildResourceDir := filepath.Join(root, "llvm-build", "lib", "clang", llvmMajor)
if _, err := os.Stat(buildResourceDir); !errors.Is(err, fs.ErrNotExist) {
return buildResourceDir
}
} else {
// We use external tools, either when installed using `go install` or
// when packaged in a Linux distribution (Linux distros typically prefer
// dynamic linking).
// Try to detect the system clang resources directory.
resourceDir := findSystemClangResources(root)
if resourceDir != "" {
return resourceDir
}
}
// Resource directory not found.
return ""
}
// Find the Clang resource dir on this particular system.
// Return the empty string when they aren't found.
func findSystemClangResources(TINYGOROOT string) string {
llvmMajor := strings.Split(llvm.Version, ".")[0]
switch runtime.GOOS {
case "linux", "android":
// Header files are typically stored in /usr/lib/clang/<version>/include.
// Tested on Fedora 39, Debian 12, and Arch Linux.
path := filepath.Join("/usr/lib/clang", llvmMajor)
_, err := os.Stat(filepath.Join(path, "include", "stdint.h"))
if err == nil {
return path
}
case "darwin":
// This assumes a Homebrew installation, like in builder/commands.go.
var prefix string
switch runtime.GOARCH {
case "amd64":
prefix = "/usr/local/opt/llvm@" + llvmMajor
case "arm64":
prefix = "/opt/homebrew/opt/llvm@" + llvmMajor
default:
return "" // very unlikely for now
}
path := fmt.Sprintf("%s/lib/clang/%s", prefix, llvmMajor)
_, err := os.Stat(path + "/include/stdint.h")
if err == nil {
return path
}
}
// Could not find it.
return ""
}
-7
View File
@@ -1,7 +0,0 @@
//go:build byollvm
package goenv
func init() {
hasBuiltinTools = true
}
+1 -11
View File
@@ -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.30.0"
var ( var (
// This variable is set at build time using -ldflags parameters. // This variable is set at build time using -ldflags parameters.
@@ -17,16 +17,6 @@ var (
GitSha1 string GitSha1 string
) )
// Return TinyGo version, either in the form 0.30.0 or as a development version
// (like 0.30.0-dev-abcd012).
func Version() string {
v := version
if strings.HasSuffix(version, "-dev") && GitSha1 != "" {
v += "-" + GitSha1
}
return v
}
// GetGorootVersion returns the major and minor version for a given GOROOT path. // GetGorootVersion returns the major and minor version for a given GOROOT path.
// If the goroot cannot be determined, (0, 0) is returned. // If the goroot cannot be determined, (0, 0) is returned.
func GetGorootVersion() (major, minor int, err error) { func GetGorootVersion() (major, minor int, err error) {
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/bash #!/bin/bash
# Docker hub does a recursive clone, then checks the branch out, # Docker hub does a recursive clone, then checks the branch out,
# so when a PR adds a submodule (or updates it), it fails. # so when a PR adds a submodule (or updates it), it fails.
git submodule update --init --recursive git submodule update --init
+3 -2
View File
@@ -18,6 +18,7 @@ import (
"errors" "errors"
"io" "io"
"io/fs" "io/fs"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"path" "path"
@@ -156,7 +157,7 @@ func listGorootMergeLinks(goroot, tinygoroot string, overrides map[string]bool)
// Add files from TinyGo. // Add files from TinyGo.
tinygoDir := filepath.Join(tinygoSrc, dir) tinygoDir := filepath.Join(tinygoSrc, dir)
tinygoEntries, err := os.ReadDir(tinygoDir) tinygoEntries, err := ioutil.ReadDir(tinygoDir)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -176,7 +177,7 @@ func listGorootMergeLinks(goroot, tinygoroot string, overrides map[string]bool)
// Add all directories from $GOROOT that are not part of the TinyGo // Add all directories from $GOROOT that are not part of the TinyGo
// overrides. // overrides.
goDir := filepath.Join(goSrc, dir) goDir := filepath.Join(goSrc, dir)
goEntries, err := os.ReadDir(goDir) goEntries, err := ioutil.ReadDir(goDir)
if err != nil { if err != nil {
return nil, err return nil, err
} }
+15 -13
View File
@@ -29,10 +29,11 @@ import (
// 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
typeChecker types.Config clangHeaders string
goroot string // synthetic GOROOT typeChecker types.Config
workingDir string goroot string // synthetic GOROOT
workingDir string
Packages map[string]*Package Packages map[string]*Package
sorted []*Package sorted []*Package
@@ -102,7 +103,7 @@ type EmbedFile struct {
// Load loads the given package with all dependencies (including the runtime // Load loads the given package with all dependencies (including the runtime
// package). Call .Parse() afterwards to parse all Go files (including CGo // package). Call .Parse() afterwards to parse all Go files (including CGo
// processing, if necessary). // processing, if necessary).
func Load(config *compileopts.Config, inputPkg string, typeChecker types.Config) (*Program, error) { func Load(config *compileopts.Config, inputPkg string, clangHeaders string, typeChecker types.Config) (*Program, error) {
goroot, err := GetCachedGoroot(config) goroot, err := GetCachedGoroot(config)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -117,12 +118,13 @@ func Load(config *compileopts.Config, inputPkg string, typeChecker types.Config)
} }
} }
p := &Program{ p := &Program{
config: config, config: config,
typeChecker: typeChecker, clangHeaders: clangHeaders,
goroot: goroot, typeChecker: typeChecker,
workingDir: wd, goroot: goroot,
Packages: make(map[string]*Package), workingDir: wd,
fset: token.NewFileSet(), Packages: make(map[string]*Package),
fset: token.NewFileSet(),
} }
// List the dependencies of this package, in raw JSON format. // List the dependencies of this package, in raw JSON format.
@@ -436,9 +438,9 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
// to call cgo.Process in that case as it will only cause issues. // to call cgo.Process in that case as it will only cause issues.
if len(p.CgoFiles) != 0 && len(files) != 0 { if len(p.CgoFiles) != 0 && len(files) != 0 {
var initialCFlags []string var initialCFlags []string
initialCFlags = append(initialCFlags, p.program.config.CFlags(true)...) initialCFlags = append(initialCFlags, p.program.config.CFlags()...)
initialCFlags = append(initialCFlags, "-I"+p.Dir) initialCFlags = append(initialCFlags, "-I"+p.Dir)
generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.ImportPath, p.program.fset, initialCFlags) generated, headerCode, cflags, ldflags, accessedFiles, errs := cgo.Process(files, p.program.workingDir, p.ImportPath, p.program.fset, initialCFlags, p.program.clangHeaders)
p.CFlags = append(initialCFlags, cflags...) p.CFlags = append(initialCFlags, cflags...)
p.CGoHeaders = headerCode p.CGoHeaders = headerCode
for path, hash := range accessedFiles { for path, hash := range accessedFiles {
+41 -27
View File
@@ -11,6 +11,7 @@ import (
"go/scanner" "go/scanner"
"go/types" "go/types"
"io" "io"
"io/ioutil"
"os" "os"
"os/exec" "os/exec"
"os/signal" "os/signal"
@@ -797,7 +798,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
needsEnvInVars = true needsEnvInVars = true
} }
} }
var args, emuArgs, env []string var args, env []string
var extraCmdEnv []string var extraCmdEnv []string
if needsEnvInVars { if needsEnvInVars {
runtimeGlobals := make(map[string]string) runtimeGlobals := make(map[string]string)
@@ -820,14 +821,13 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
} else if config.EmulatorName() == "wasmtime" { } else if config.EmulatorName() == "wasmtime" {
// Wasmtime needs some special flags to pass environment variables // Wasmtime needs some special flags to pass environment variables
// and allow reading from the current directory. // and allow reading from the current directory.
emuArgs = append(emuArgs, "--dir=.") args = append(args, "--dir=.")
for _, v := range environmentVars { for _, v := range environmentVars {
emuArgs = append(emuArgs, "--env", v) args = append(args, "--env", v)
} }
if len(cmdArgs) != 0 { if len(cmdArgs) != 0 {
// Use of '--' argument no longer necessary as of Wasmtime v14: // mark end of wasmtime arguments and start of program ones: --
// https://github.com/bytecodealliance/wasmtime/pull/6946 args = append(args, "--")
// args = append(args, "--")
args = append(args, cmdArgs...) args = append(args, cmdArgs...)
} }
@@ -877,7 +877,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
return result, err return result, err
} }
name = emulator[0] name = emulator[0]
emuArgs = append(emuArgs, emulator[1:]...) emuArgs := append([]string(nil), emulator[1:]...)
args = append(emuArgs, args...) args = append(emuArgs, args...)
} }
var cmd *exec.Cmd var cmd *exec.Cmd
@@ -1212,10 +1212,15 @@ func getBMPPorts() (gdbPort, uartPort string, err error) {
} }
func usage(command string) { func usage(command string) {
version := goenv.Version
if strings.HasSuffix(version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
}
switch command { switch command {
default: default:
fmt.Fprintln(os.Stderr, "TinyGo is a Go compiler for small places.") fmt.Fprintln(os.Stderr, "TinyGo is a Go compiler for small places.")
fmt.Fprintln(os.Stderr, "version:", goenv.Version()) fmt.Fprintln(os.Stderr, "version:", version)
fmt.Fprintf(os.Stderr, "usage: %s <command> [arguments]\n", os.Args[0]) fmt.Fprintf(os.Stderr, "usage: %s <command> [arguments]\n", os.Args[0])
fmt.Fprintln(os.Stderr, "\ncommands:") fmt.Fprintln(os.Stderr, "\ncommands:")
fmt.Fprintln(os.Stderr, " build: compile packages and dependencies") fmt.Fprintln(os.Stderr, " build: compile packages and dependencies")
@@ -1437,7 +1442,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,29 +1737,35 @@ func main() {
os.Exit(1) os.Exit(1)
} }
case "monitor": case "monitor":
if *info { err := Monitor("", *port, options)
serialPortInfo, err := ListSerialPorts() handleCompilerError(err)
handleCompilerError(err)
for _, s := range serialPortInfo {
fmt.Printf("%s %4s %4s %s\n", s.Name, s.VID, s.PID, s.Target)
}
} else {
err := Monitor("", *port, options)
handleCompilerError(err)
}
case "targets": case "targets":
specs, err := compileopts.GetTargetSpecs() dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
entries, err := ioutil.ReadDir(dir)
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "could not list targets:", err) fmt.Fprintln(os.Stderr, "could not list targets:", err)
os.Exit(1) os.Exit(1)
return return
} }
names := []string{} for _, entry := range entries {
for key := range specs { if !entry.Mode().IsRegular() || !strings.HasSuffix(entry.Name(), ".json") {
names = append(names, key) // Only inspect JSON files.
} continue
sort.Strings(names) }
for _, name := range names { path := filepath.Join(dir, entry.Name())
spec, err := compileopts.LoadTarget(&compileopts.Options{Target: path})
if err != nil {
fmt.Fprintln(os.Stderr, "could not list target:", err)
os.Exit(1)
return
}
if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == "" {
// This doesn't look like a regular target file, but rather like
// a parent target (such as targets/cortex-m.json).
continue
}
name := entry.Name()
name = name[:len(name)-5]
fmt.Println(name) fmt.Println(name)
} }
case "info": case "info":
@@ -1864,7 +1874,11 @@ func main() {
if s, err := goenv.GorootVersionString(); err == nil { if s, err := goenv.GorootVersionString(); err == nil {
goversion = s goversion = s
} }
fmt.Printf("tinygo version %s %s/%s (using go version %s and LLVM version %s)\n", goenv.Version(), runtime.GOOS, runtime.GOARCH, goversion, llvm.Version) version := goenv.Version
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
}
fmt.Printf("tinygo version %s %s/%s (using go version %s and LLVM version %s)\n", version, runtime.GOOS, runtime.GOARCH, goversion, llvm.Version)
case "env": case "env":
if flag.NArg() == 0 { if flag.NArg() == 0 {
// Show all environment variables. // Show all environment variables.
-56
View File
@@ -13,15 +13,12 @@ import (
"os/signal" "os/signal"
"regexp" "regexp"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/mattn/go-tty" "github.com/mattn/go-tty"
"github.com/tinygo-org/tinygo/builder" "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"
"go.bug.st/serial/enumerator"
) )
// Monitor connects to the given port and reads/writes the serial port. // Monitor connects to the given port and reads/writes the serial port.
@@ -131,59 +128,6 @@ func Monitor(executable, port string, options *compileopts.Options) error {
return <-errCh return <-errCh
} }
// SerialPortInfo is a structure that holds information about the port and its
// associated TargetSpec.
type SerialPortInfo struct {
Name string
IsUSB bool
VID string
PID string
Target string
Spec *compileopts.TargetSpec
}
// ListSerialPort returns serial port information and any detected TinyGo
// target.
func ListSerialPorts() ([]SerialPortInfo, error) {
maps, err := compileopts.GetTargetSpecs()
if err != nil {
return nil, err
}
portsList, err := enumerator.GetDetailedPortsList()
if err != nil {
return nil, err
}
serialPortInfo := []SerialPortInfo{}
for _, p := range portsList {
info := SerialPortInfo{
Name: p.Name,
IsUSB: p.IsUSB,
VID: p.VID,
PID: p.PID,
}
vid := strings.ToLower(p.VID)
pid := strings.ToLower(p.PID)
for k, v := range maps {
usbInterfaces := v.SerialPort
for _, s := range usbInterfaces {
parts := strings.Split(s, ":")
if len(parts) != 2 {
continue
}
if vid == strings.ToLower(parts[0]) && pid == strings.ToLower(parts[1]) {
info.Target = k
info.Spec = v
}
}
}
serialPortInfo = append(serialPortInfo, info)
}
return serialPortInfo, nil
}
var addressMatch = regexp.MustCompile(`^panic: runtime error at 0x([0-9a-f]+): `) var addressMatch = regexp.MustCompile(`^panic: runtime error at 0x([0-9a-f]+): `)
// Extract the address from the "panic: runtime error at" message. // Extract the address from the "panic: runtime error at" message.
-21
View File
@@ -1,21 +0,0 @@
package main
import (
"encoding/hex"
"machine"
"time"
)
func main() {
time.Sleep(2 * time.Second)
// For efficiency, it's best to get the device ID once and cache it
// (e.g. on RP2040 XIP flash and interrupts disabled for period of
// retrieving the hardware ID from ROM chip)
id := machine.DeviceID()
for {
println("Device ID:", hex.EncodeToString(id))
time.Sleep(1 * time.Second)
}
}
+1 -3
View File
@@ -24,9 +24,7 @@ func main() {
// Schedule and enable recurring interrupt. // Schedule and enable recurring interrupt.
// The callback function is executed in the context of an interrupt handler, // The callback function is executed in the context of an interrupt handler,
// so regular restrictions for this sort of code apply: no blocking, no memory allocation, etc. // so regular restructions for this sort of code apply: no blocking, no memory allocation, etc.
// Please check the online documentation for the details about interrupts:
// https://tinygo.org/docs/concepts/compiler-internals/interrupts/
delay := time.Minute + 12*time.Second delay := time.Minute + 12*time.Second
machine.RTC.SetInterrupt(uint32(delay.Seconds()), true, func() { println("Peekaboo!") }) machine.RTC.SetInterrupt(uint32(delay.Seconds()), true, func() { println("Peekaboo!") })
-17
View File
@@ -1,17 +0,0 @@
//go:build rp2040 || nrf || sam
package machine
// DeviceID returns an identifier that is unique within
// a particular chipset.
//
// The identity is one burnt into the MCU itself, or the
// flash chip at time of manufacture.
//
// It's possible that two different vendors may allocate
// the same DeviceID, so callers should take this into
// account if needing to generate a globally unique id.
//
// The length of the hardware ID is vendor-specific, but
// 8 bytes (64 bits) and 16 bytes (128 bits) are common.
var _ = (func() []byte)(DeviceID)
+1 -13
View File
@@ -1,4 +1,4 @@
//go:build atmega || nrf || sam || stm32 || fe310 || k210 || rp2040 || mimxrt1062 //go:build atmega || nrf || sam || stm32 || fe310 || k210 || rp2040
package machine package machine
@@ -6,17 +6,6 @@ import (
"errors" "errors"
) )
// If you are getting a compile error on this line please check to see you've
// correctly implemented the methods on the I2C type. They must match
// the i2cController interface method signatures type to type perfectly.
// If not implementing the I2C type please remove your target from the build tags
// at the top of this file.
var _ interface { // 2
Configure(config I2CConfig) error
Tx(addr uint16, w, r []byte) error
SetBaudRate(br uint32) error
} = (*I2C)(nil)
// TWI_FREQ is the I2C bus speed. Normally either 100 kHz, or 400 kHz for high-speed bus. // TWI_FREQ is the I2C bus speed. Normally either 100 kHz, or 400 kHz for high-speed bus.
// //
// Deprecated: use 100 * machine.KHz or 400 * machine.KHz instead. // Deprecated: use 100 * machine.KHz or 400 * machine.KHz instead.
@@ -36,7 +25,6 @@ var (
errI2CBusError = errors.New("I2C bus error") errI2CBusError = errors.New("I2C bus error")
errI2COverflow = errors.New("I2C receive buffer overflow") errI2COverflow = errors.New("I2C receive buffer overflow")
errI2COverread = errors.New("I2C transmit buffer overflow") errI2COverread = errors.New("I2C transmit buffer overflow")
errI2CNotImplemented = errors.New("I2C operation not yet implemented")
) )
// I2CTargetEvent reflects events on the I2C bus // I2CTargetEvent reflects events on the I2C bus
+1 -6
View File
@@ -31,11 +31,6 @@ func (i2c *I2C) Configure(config I2CConfig) error {
// Activate internal pullups for twi. // Activate internal pullups for twi.
avr.PORTC.SetBits((avr.DIDR0_ADC4D | avr.DIDR0_ADC5D)) avr.PORTC.SetBits((avr.DIDR0_ADC4D | avr.DIDR0_ADC5D))
return i2c.SetBaudRate(config.Frequency)
}
// SetBaudRate sets the communication speed for I2C.
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)) avr.TWSR.SetBits((avr.TWSR_TWPS0 | avr.TWSR_TWPS1))
@@ -43,7 +38,7 @@ func (i2c *I2C) SetBaudRate(br uint32) error {
// 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)) avr.TWBR.Set(uint8(((CPUFrequency() / config.Frequency) - 16) / 2))
// Enable twi module. // Enable twi module.
avr.TWCR.Set(avr.TWCR_TWEN) avr.TWCR.Set(avr.TWCR_TWEN)
-31
View File
@@ -1,31 +0,0 @@
//go:build sam
package machine
import (
"runtime/volatile"
"unsafe"
)
var deviceID [16]byte
// DeviceID returns an identifier that is unique within
// a particular chipset.
//
// The identity is one burnt into the MCU itself, or the
// flash chip at time of manufacture.
//
// It's possible that two different vendors may allocate
// the same DeviceID, so callers should take this into
// account if needing to generate a globally unique id.
//
// The length of the hardware ID is vendor-specific, but
// 8 bytes (64 bits) and 16 bytes (128 bits) are common.
func DeviceID() []byte {
for i := 0; i < len(deviceID); i++ {
word := (*volatile.Register32)(unsafe.Pointer(deviceIDAddr[i/4])).Get()
deviceID[i] = byte(word >> ((i % 4) * 8))
}
return deviceID[:]
}
+2 -6
View File
@@ -18,9 +18,6 @@ import (
const deviceName = sam.Device const deviceName = sam.Device
// DS40001882F, Section 10.3.3: Serial Number
var deviceIDAddr = []uintptr{0x0080A00C, 0x0080A040, 0x0080A044, 0x0080A048}
const ( const (
PinAnalog PinMode = 1 PinAnalog PinMode = 1
PinSERCOM PinMode = 2 PinSERCOM PinMode = 2
@@ -735,13 +732,12 @@ func (i2c *I2C) Configure(config I2CConfig) error {
return nil return nil
} }
// SetBaudRate sets the communication speed for I2C. // SetBaudRate sets the communication speed for the I2C.
func (i2c *I2C) SetBaudRate(br uint32) error { func (i2c *I2C) SetBaudRate(br uint32) {
// Synchronous arithmetic baudrate, via Arduino SAMD implementation: // Synchronous arithmetic baudrate, via Arduino SAMD implementation:
// SystemCoreClock / ( 2 * baudrate) - 5 - (((SystemCoreClock / 1000000) * WIRE_RISE_TIME_NANOSECONDS) / (2 * 1000)); // SystemCoreClock / ( 2 * baudrate) - 5 - (((SystemCoreClock / 1000000) * WIRE_RISE_TIME_NANOSECONDS) / (2 * 1000));
baud := CPUFrequency()/(2*br) - 5 - (((CPUFrequency() / 1000000) * riseTimeNanoseconds) / (2 * 1000)) baud := CPUFrequency()/(2*br) - 5 - (((CPUFrequency() / 1000000) * riseTimeNanoseconds) / (2 * 1000))
i2c.Bus.BAUD.Set(baud) i2c.Bus.BAUD.Set(baud)
return nil
} }
// Tx does a single I2C transaction at the specified address. // Tx does a single I2C transaction at the specified address.
+2 -151
View File
@@ -18,9 +18,6 @@ import (
const deviceName = sam.Device const deviceName = sam.Device
// DS60001507, Section 9.6: Serial Number
var deviceIDAddr = []uintptr{0x008061FC, 0x00806010, 0x00806014, 0x00806018}
func CPUFrequency() uint32 { func CPUFrequency() uint32 {
return 120000000 return 120000000
} }
@@ -683,56 +680,6 @@ func (p Pin) getPinGrouping() (uint8, uint8) {
return group, pin_in_group return group, pin_in_group
} }
// Static DMA channel allocation.
// If there are a lot of DMA using peripherals, we might need to switch to
// dynamic allocation instead.
const (
dmaChannelSERCOM0 = iota
dmaChannelSERCOM1
dmaChannelSERCOM2
dmaChannelSERCOM3
dmaChannelSERCOM4
dmaChannelSERCOM5
dmaChannelSERCOM6
dmaChannelSERCOM7
dmaNumChannels
)
// DMA descriptor structure. This structure is defined by the hardware, and is
// described by "22.9 Register Summary - SRAM" in the datasheet.
type dmaDescriptor struct {
btctrl uint16
btcnt uint16
srcaddr unsafe.Pointer
dstaddr unsafe.Pointer
descaddr unsafe.Pointer
}
//go:align 16
var dmaDescriptorSection [dmaNumChannels]dmaDescriptor
//go:align 16
var dmaDescriptorWritebackSection [dmaNumChannels]dmaDescriptor
// Enable and configure the DMAC peripheral if it hasn't been enabled already.
func enableDMAC() {
if !sam.DMAC.CTRL.HasBits(sam.DMAC_CTRL_DMAENABLE) {
// Init DMAC.
// First configure the clocks, then configure the DMA descriptors. Those
// descriptors must live in SRAM and must be aligned on a 16-byte
// boundary.
// Some examples:
// http://www.lucadavidian.com/2018/03/08/wifi-controlled-neo-pixels-strips/
// https://svn.larosterna.com/oss/trunk/arduino/zerotimer/zerodma.cpp
sam.MCLK.AHBMASK.SetBits(sam.MCLK_AHBMASK_DMAC_)
sam.DMAC.BASEADDR.Set(uint32(uintptr(unsafe.Pointer(&dmaDescriptorSection))))
sam.DMAC.WRBADDR.Set(uint32(uintptr(unsafe.Pointer(&dmaDescriptorWritebackSection))))
// Enable peripheral with all priorities.
sam.DMAC.CTRL.SetBits(sam.DMAC_CTRL_DMAENABLE | sam.DMAC_CTRL_LVLEN0 | sam.DMAC_CTRL_LVLEN1 | sam.DMAC_CTRL_LVLEN2 | sam.DMAC_CTRL_LVLEN3)
}
}
// InitADC initializes the ADC. // InitADC initializes the ADC.
func InitADC() { func InitADC() {
// ADC Bias Calibration // ADC Bias Calibration
@@ -1281,13 +1228,12 @@ func (i2c *I2C) Configure(config I2CConfig) error {
return nil return nil
} }
// SetBaudRate sets the communication speed for I2C. // SetBaudRate sets the communication speed for the I2C.
func (i2c *I2C) SetBaudRate(br uint32) error { func (i2c *I2C) SetBaudRate(br uint32) {
// Synchronous arithmetic baudrate, via Adafruit SAMD51 implementation: // Synchronous arithmetic baudrate, via Adafruit SAMD51 implementation:
// sercom->I2CM.BAUD.bit.BAUD = SERCOM_FREQ_REF / ( 2 * baudrate) - 1 ; // sercom->I2CM.BAUD.bit.BAUD = SERCOM_FREQ_REF / ( 2 * baudrate) - 1 ;
baud := SERCOM_FREQ_REF/(2*br) - 1 baud := SERCOM_FREQ_REF/(2*br) - 1
i2c.Bus.BAUD.Set(baud) i2c.Bus.BAUD.Set(baud)
return nil
} }
// Tx does a single I2C transaction at the specified address. // Tx does a single I2C transaction at the specified address.
@@ -1702,101 +1648,6 @@ func (spi SPI) txrx(tx, rx []byte) {
rx[len(rx)-1] = byte(spi.Bus.DATA.Get()) rx[len(rx)-1] = byte(spi.Bus.DATA.Get())
} }
// Channel to be used for SPI transfers.
// These channels are currently statically allocated.
func (spi SPI) dmaTxChannel() uint8 {
return dmaChannelSERCOM0 + spi.SERCOM
}
// IsAsync returns whether the SPI supports async operation (usually DMA).
//
// It returns true on the SAM D5x chips.
func (spi SPI) IsAsync() bool {
return true
}
// Start a transfer in the background.
//
// After this, another StartTx() or Wait() must be called. The provided byte
// slices (tx and rx) may only be accessed again after Wait() was called.
func (s SPI) StartTx(tx, rx []byte) error {
// Check whether we support doing this transfer using DMA.
if len(rx) != 0 {
return s.Tx(tx, rx)
}
if len(tx) == 0 {
return nil // nothing to send/receive
}
if len(tx) != int(uint16(len(tx))) {
// The transfer size is a 16-bit field.
// TODO: chain multiple transfers in some way when encountering these
// large buffer sizes. They're not currently implemented because
// transferring 64kB of data is less commonly done.
return s.Tx(tx, rx)
}
// Enable DMAC (if not already enabled).
enableDMAC()
// Wait until a possible previous transfer has been completed.
s.Wait()
// Configure the DMA channel, if it hasn't been configured already.
dstaddr := unsafe.Pointer(&s.Bus.DATA.Reg)
if dmaDescriptorSection[s.dmaTxChannel()].dstaddr != dstaddr {
// Configure channel descriptor.
dmaDescriptorSection[s.dmaTxChannel()] = dmaDescriptor{
btctrl: (1 << 0) | // VALID: Descriptor Valid
(0 << 3) | // BLOCKACT=NOACT: Block Action
(1 << 10) | // SRCINC: Source Address Increment Enable
(0 << 11) | // DSTINC: Destination Address Increment Enable
(1 << 12) | // STEPSEL=SRC: Step Selection
(0 << 13), // STEPSIZE=X1: Address Increment Step Size
dstaddr: dstaddr,
}
// Reset channel.
sam.DMAC.CHANNEL[s.dmaTxChannel()].CHCTRLA.ClearBits(sam.DMAC_CHANNEL_CHCTRLA_ENABLE)
sam.DMAC.CHANNEL[s.dmaTxChannel()].CHCTRLA.SetBits(sam.DMAC_CHANNEL_CHCTRLA_SWRST)
// Configure channel.
sam.DMAC.CHANNEL[s.dmaTxChannel()].CHPRILVL.Set(0)
sam.DMAC.CHANNEL[s.dmaTxChannel()].CHCTRLA.Set((sam.DMAC_CHANNEL_CHCTRLA_TRIGACT_BURST << sam.DMAC_CHANNEL_CHCTRLA_TRIGACT_Pos) |
(s.triggerSource() << sam.DMAC_CHANNEL_CHCTRLA_TRIGSRC_Pos) |
(sam.DMAC_CHANNEL_CHCTRLA_BURSTLEN_SINGLE << sam.DMAC_CHANNEL_CHCTRLA_BURSTLEN_Pos))
}
// For some reason, you have to provide the address just past the end of the
// array instead of the address of the array.
descriptor := &dmaDescriptorSection[s.dmaTxChannel()]
descriptor.srcaddr = unsafe.Pointer(uintptr(unsafe.Pointer(&tx[0])) + uintptr(len(tx)))
descriptor.btcnt = uint16(len(tx)) // beat count
// Start the transfer.
sam.DMAC.CHANNEL[s.dmaTxChannel()].CHCTRLA.SetBits(sam.DMAC_CHANNEL_CHCTRLA_ENABLE)
return nil
}
// Wait until all active transactions (started by StartTx) have finished. The
// buffers provided in StartTx will be available after this method returns.
func (spi SPI) Wait() error {
// Wait until the previous SPI transfer completed.
// This is basically the same thing as in SPI.tx.
// TODO: maybe block (and sleep) until the transfer has completed?
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_TXC) {
}
// read to clear RXC register
for spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) {
spi.Bus.DATA.Get()
}
return nil
}
// The QSPI peripheral on ATSAMD51 is only available on the following pins // The QSPI peripheral on ATSAMD51 is only available on the following pins
const ( const (
QSPI_SCK = PB10 QSPI_SCK = PB10
-21
View File
@@ -62,27 +62,6 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
} }
} }
// DMA trigger source
func (spi SPI) triggerSource() (tx uint32) {
// See TRIGSRC field of CHCTRLA register for description of these constants.
switch spi.Bus {
case sam.SERCOM0_SPIM:
return 0x05
case sam.SERCOM1_SPIM:
return 0x07
case sam.SERCOM2_SPIM:
return 0x09
case sam.SERCOM3_SPIM:
return 0x0A
case sam.SERCOM4_SPIM:
return 0x0C
case sam.SERCOM5_SPIM:
return 0x0E
default:
return 0 // should be unreachable
}
}
// This chip has three TCC peripherals, which have PWM as one feature. // This chip has three TCC peripherals, which have PWM as one feature.
var ( var (
TCC0 = (*TCC)(sam.TCC0) TCC0 = (*TCC)(sam.TCC0)
-21
View File
@@ -62,27 +62,6 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
} }
} }
// DMA trigger source
func (spi SPI) triggerSource() (tx uint32) {
// See TRIGSRC field of CHCTRLA register for description of these constants.
switch spi.Bus {
case sam.SERCOM0_SPIM:
return 0x05
case sam.SERCOM1_SPIM:
return 0x07
case sam.SERCOM2_SPIM:
return 0x09
case sam.SERCOM3_SPIM:
return 0x0B
case sam.SERCOM4_SPIM:
return 0x0D
case sam.SERCOM5_SPIM:
return 0x0F
default:
return 0 // should be unreachable
}
}
// This chip has five TCC peripherals, which have PWM as one feature. // This chip has five TCC peripherals, which have PWM as one feature.
var ( var (
TCC0 = (*TCC)(sam.TCC0) TCC0 = (*TCC)(sam.TCC0)
-21
View File
@@ -62,27 +62,6 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
} }
} }
// DMA trigger source
func (spi SPI) triggerSource() (tx uint32) {
// See TRIGSRC field of CHCTRLA register for description of these constants.
switch spi.Bus {
case sam.SERCOM0_SPIM:
return 0x05
case sam.SERCOM1_SPIM:
return 0x07
case sam.SERCOM2_SPIM:
return 0x09
case sam.SERCOM3_SPIM:
return 0x0A
case sam.SERCOM4_SPIM:
return 0x0C
case sam.SERCOM5_SPIM:
return 0x0E
default:
return 0 // should be unreachable
}
}
// This chip has five TCC peripherals, which have PWM as one feature. // This chip has five TCC peripherals, which have PWM as one feature.
var ( var (
TCC0 = (*TCC)(sam.TCC0) TCC0 = (*TCC)(sam.TCC0)
-25
View File
@@ -76,31 +76,6 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
} }
} }
// DMA trigger source
func (spi SPI) triggerSource() (tx uint32) {
// See TRIGSRC field of CHCTRLA register for description of these constants.
switch spi.Bus {
case sam.SERCOM0_SPIM:
return 0x05
case sam.SERCOM1_SPIM:
return 0x07
case sam.SERCOM2_SPIM:
return 0x09
case sam.SERCOM3_SPIM:
return 0x0A
case sam.SERCOM4_SPIM:
return 0x0C
case sam.SERCOM5_SPIM:
return 0x0E
case sam.SERCOM6_SPIM:
return 0x10
case sam.SERCOM7_SPIM:
return 0x12
default:
return 0 // should be unreachable
}
}
// This chip has five TCC peripherals, which have PWM as one feature. // This chip has five TCC peripherals, which have PWM as one feature.
var ( var (
TCC0 = (*TCC)(sam.TCC0) TCC0 = (*TCC)(sam.TCC0)
-25
View File
@@ -76,31 +76,6 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
} }
} }
// DMA trigger source
func (spi SPI) triggerSource() (tx uint32) {
// See TRIGSRC field of CHCTRLA register for description of these constants.
switch spi.Bus {
case sam.SERCOM0_SPIM:
return 0x05
case sam.SERCOM1_SPIM:
return 0x07
case sam.SERCOM2_SPIM:
return 0x09
case sam.SERCOM3_SPIM:
return 0x0A
case sam.SERCOM4_SPIM:
return 0x0C
case sam.SERCOM5_SPIM:
return 0x0E
case sam.SERCOM6_SPIM:
return 0x10
case sam.SERCOM7_SPIM:
return 0x12
default:
return 0 // should be unreachable
}
}
// This chip has five TCC peripherals, which have PWM as one feature. // This chip has five TCC peripherals, which have PWM as one feature.
var ( var (
TCC0 = (*TCC)(sam.TCC0) TCC0 = (*TCC)(sam.TCC0)
-21
View File
@@ -62,27 +62,6 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
} }
} }
// DMA trigger source
func (spi SPI) triggerSource() (tx uint32) {
// See TRIGSRC field of CHCTRLA register for description of these constants.
switch spi.Bus {
case sam.SERCOM0_SPIM:
return 0x05
case sam.SERCOM1_SPIM:
return 0x07
case sam.SERCOM2_SPIM:
return 0x09
case sam.SERCOM3_SPIM:
return 0x0A
case sam.SERCOM4_SPIM:
return 0x0C
case sam.SERCOM5_SPIM:
return 0x0E
default:
return 0 // should be unreachable
}
}
// This chip has five TCC peripherals, which have PWM as one feature. // This chip has five TCC peripherals, which have PWM as one feature.
var ( var (
TCC0 = (*TCC)(sam.TCC0) TCC0 = (*TCC)(sam.TCC0)
-25
View File
@@ -76,31 +76,6 @@ func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
} }
} }
// DMA trigger source
func (spi SPI) triggerSource() (tx uint32) {
// See TRIGSRC field of CHCTRLA register for description of these constants.
switch spi.Bus {
case sam.SERCOM0_SPIM:
return 0x05
case sam.SERCOM1_SPIM:
return 0x07
case sam.SERCOM2_SPIM:
return 0x09
case sam.SERCOM3_SPIM:
return 0x0A
case sam.SERCOM4_SPIM:
return 0x0C
case sam.SERCOM5_SPIM:
return 0x0E
case sam.SERCOM6_SPIM:
return 0x10
case sam.SERCOM7_SPIM:
return 0x12
default:
return 0 // should be unreachable
}
}
// This chip has five TCC peripherals, which have PWM as one feature. // This chip has five TCC peripherals, which have PWM as one feature.
var ( var (
TCC0 = (*TCC)(sam.TCC0) TCC0 = (*TCC)(sam.TCC0)
+5 -13
View File
@@ -229,10 +229,9 @@ type I2CConfig struct {
SDA Pin SDA Pin
} }
var i2cClockFrequency uint32 = 32000000
// Configure is intended to setup the I2C interface. // Configure is intended to setup the I2C interface.
func (i2c *I2C) Configure(config I2CConfig) error { func (i2c *I2C) Configure(config I2CConfig) error {
var i2cClockFrequency uint32 = 32000000
if config.Frequency == 0 { if config.Frequency == 0 {
config.Frequency = 100 * KHz config.Frequency = 100 * KHz
} }
@@ -242,17 +241,7 @@ func (i2c *I2C) Configure(config I2CConfig) error {
config.SCL = I2C0_SCL_PIN config.SCL = I2C0_SCL_PIN
} }
i2c.SetBaudRate(config.Frequency) var prescaler = i2cClockFrequency/(5*config.Frequency) - 1
config.SDA.Configure(PinConfig{Mode: PinI2C})
config.SCL.Configure(PinConfig{Mode: PinI2C})
return nil
}
// SetBaudRate sets the communication speed for I2C.
func (i2c *I2C) SetBaudRate(br uint32) error {
var prescaler = i2cClockFrequency/(5*br) - 1
// disable controller before setting the prescale registers // disable controller before setting the prescale registers
i2c.Bus.CTR.ClearBits(sifive.I2C_CTR_EN) i2c.Bus.CTR.ClearBits(sifive.I2C_CTR_EN)
@@ -264,6 +253,9 @@ func (i2c *I2C) SetBaudRate(br uint32) error {
// enable controller // enable controller
i2c.Bus.CTR.SetBits(sifive.I2C_CTR_EN) i2c.Bus.CTR.SetBits(sifive.I2C_CTR_EN)
config.SDA.Configure(PinConfig{Mode: PinI2C})
config.SCL.Configure(PinConfig{Mode: PinI2C})
return nil return nil
} }
+1 -11
View File
@@ -57,9 +57,8 @@ type SPIConfig struct {
Mode uint8 Mode uint8
} }
func (spi SPI) Configure(config SPIConfig) error { func (spi SPI) Configure(config SPIConfig) {
spiConfigure(spi.Bus, config.SCK, config.SDO, config.SDI) spiConfigure(spi.Bus, config.SCK, config.SDO, config.SDI)
return nil
} }
// Transfer writes/reads a single byte using the SPI interface. // Transfer writes/reads a single byte using the SPI interface.
@@ -108,12 +107,6 @@ func (i2c *I2C) Configure(config I2CConfig) error {
return nil return nil
} }
// SetBaudRate sets the I2C frequency.
func (i2c *I2C) SetBaudRate(br uint32) error {
i2cSetBaudRate(i2c.Bus, br)
return nil
}
// Tx does a single I2C transaction at the specified address. // Tx does a single I2C transaction at the specified address.
func (i2c *I2C) Tx(addr uint16, w, r []byte) error { func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
i2cTransfer(i2c.Bus, &w[0], len(w), &r[0], len(r)) i2cTransfer(i2c.Bus, &w[0], len(w), &r[0], len(r))
@@ -124,9 +117,6 @@ func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
//export __tinygo_i2c_configure //export __tinygo_i2c_configure
func i2cConfigure(bus uint8, scl Pin, sda Pin) func i2cConfigure(bus uint8, scl Pin, sda Pin)
//export __tinygo_i2c_set_baud_rate
func i2cSetBaudRate(bus uint8, br uint32)
//export __tinygo_i2c_transfer //export __tinygo_i2c_transfer
func i2cTransfer(bus uint8, w *byte, wlen int, r *byte, rlen int) int func i2cTransfer(bus uint8, w *byte, wlen int, r *byte, rlen int) int
+6 -13
View File
@@ -563,19 +563,7 @@ func (i2c *I2C) Configure(config I2CConfig) error {
config.SCL.SetFPIOAFunction(FUNC_I2C2_SCLK) config.SCL.SetFPIOAFunction(FUNC_I2C2_SCLK)
} }
i2c.SetBaudRate(config.Frequency) div := CPUFrequency() / config.Frequency / 16
i2c.Bus.INTR_MASK.Set(0)
i2c.Bus.DMA_CR.Set(0x03)
i2c.Bus.DMA_RDLR.Set(0)
i2c.Bus.DMA_TDLR.Set(0x4)
return nil
}
// SetBaudRate sets the communication speed for I2C.
func (i2c *I2C) SetBaudRate(br uint32) error {
div := CPUFrequency() / br / 16
// Disable controller before setting the prescale register. // Disable controller before setting the prescale register.
i2c.Bus.ENABLE.Set(0) i2c.Bus.ENABLE.Set(0)
@@ -586,6 +574,11 @@ func (i2c *I2C) SetBaudRate(br uint32) error {
i2c.Bus.SS_SCL_HCNT.Set(uint32(div)) i2c.Bus.SS_SCL_HCNT.Set(uint32(div))
i2c.Bus.SS_SCL_LCNT.Set(uint32(div)) i2c.Bus.SS_SCL_LCNT.Set(uint32(div))
i2c.Bus.INTR_MASK.Set(0)
i2c.Bus.DMA_CR.Set(0x03)
i2c.Bus.DMA_RDLR.Set(0)
i2c.Bus.DMA_TDLR.Set(0x4)
return nil return nil
} }
+19 -14
View File
@@ -6,6 +6,19 @@ package machine
import ( import (
"device/nxp" "device/nxp"
"errors"
)
var (
errI2CWriteTimeout = errors.New("I2C timeout during write")
errI2CReadTimeout = errors.New("I2C timeout during read")
errI2CBusReadyTimeout = errors.New("I2C timeout on bus ready")
errI2CSignalStartTimeout = errors.New("I2C timeout on signal start")
errI2CSignalReadTimeout = errors.New("I2C timeout on signal read")
errI2CSignalStopTimeout = errors.New("I2C timeout on signal stop")
errI2CAckExpected = errors.New("I2C error: expected ACK not NACK")
errI2CBusError = errors.New("I2C bus error")
errI2CNotConfigured = errors.New("I2C interface is not yet configured")
) )
// I2CConfig is used to store config info for I2C. // I2CConfig is used to store config info for I2C.
@@ -137,7 +150,7 @@ func (i2c *I2C) setPins(c I2CConfig) (sda, scl Pin) {
} }
// Configure is intended to setup an I2C interface for transmit/receive. // Configure is intended to setup an I2C interface for transmit/receive.
func (i2c *I2C) Configure(config I2CConfig) error { func (i2c *I2C) Configure(config I2CConfig) {
// init pins // init pins
sda, scl := i2c.setPins(config) sda, scl := i2c.setPins(config)
@@ -156,14 +169,6 @@ func (i2c *I2C) Configure(config I2CConfig) error {
// reset clock and registers, and enable LPI2C module interface // reset clock and registers, and enable LPI2C module interface
i2c.reset(freq) i2c.reset(freq)
return nil
}
// SetBaudRate sets the communication speed for I2C.
func (i2c I2C) SetBaudRate(br uint32) error {
// TODO: implement
return errI2CNotImplemented
} }
func (i2c I2C) Tx(addr uint16, w, r []byte) error { func (i2c I2C) Tx(addr uint16, w, r []byte) error {
@@ -207,13 +212,13 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
return nil return nil
} }
// WriteRegisterEx transmits first the register and then the data to the // WriteRegister transmits first the register and then the data to the
// peripheral device. // peripheral device.
// //
// Many I2C-compatible devices are organized in terms of registers. This method // Many I2C-compatible devices are organized in terms of registers. This method
// is a shortcut to easily write to such registers. Also, it only works for // is a shortcut to easily write to such registers. Also, it only works for
// devices with 7-bit addresses, which is the vast majority. // devices with 7-bit addresses, which is the vast majority.
func (i2c I2C) WriteRegisterEx(address uint8, register uint8, data []byte) error { func (i2c I2C) WriteRegister(address uint8, register uint8, data []byte) error {
option := transferOption{ option := transferOption{
flags: transferDefault, // transfer options bit mask (0 = normal transfer) flags: transferDefault, // transfer options bit mask (0 = normal transfer)
peripheral: uint16(address), // 7-bit peripheral address peripheral: uint16(address), // 7-bit peripheral address
@@ -227,13 +232,13 @@ func (i2c I2C) WriteRegisterEx(address uint8, register uint8, data []byte) error
return nil return nil
} }
// ReadRegisterEx transmits the register, restarts the connection as a read // ReadRegister transmits the register, restarts the connection as a read
// operation, and reads the response. // operation, and reads the response.
// //
// Many I2C-compatible devices are organized in terms of registers. This method // Many I2C-compatible devices are organized in terms of registers. This method
// is a shortcut to easily read such registers. Also, it only works for devices // is a shortcut to easily read such registers. Also, it only works for devices
// with 7-bit addresses, which is the vast majority. // with 7-bit addresses, which is the vast majority.
func (i2c I2C) ReadRegisterEx(address uint8, register uint8, data []byte) error { func (i2c I2C) ReadRegister(address uint8, register uint8, data []byte) error {
option := transferOption{ option := transferOption{
flags: transferDefault, // transfer options bit mask (0 = normal transfer) flags: transferDefault, // transfer options bit mask (0 = normal transfer)
peripheral: uint16(address), // 7-bit peripheral address peripheral: uint16(address), // 7-bit peripheral address
@@ -555,7 +560,7 @@ func (i2c *I2C) controllerReceive(rxBuffer []byte) resultFlag {
return result return result
} }
// controllerTransmit performs a polling transmit transfer on the I2C bus. // controllerReceive performs a polling transmit transfer on the I2C bus.
func (i2c *I2C) controllerTransmit(txBuffer []byte) resultFlag { func (i2c *I2C) controllerTransmit(txBuffer []byte) resultFlag {
txSize := len(txBuffer) txSize := len(txBuffer)
for txSize > 0 { for txSize > 0 {
+1 -3
View File
@@ -68,7 +68,7 @@ var (
) )
// Configure is intended to setup an SPI interface for transmit/receive. // Configure is intended to setup an SPI interface for transmit/receive.
func (spi *SPI) Configure(config SPIConfig) error { func (spi *SPI) Configure(config SPIConfig) {
const defaultSpiFreq = 4000000 // 4 MHz const defaultSpiFreq = 4000000 // 4 MHz
@@ -132,8 +132,6 @@ func (spi *SPI) Configure(config SPIConfig) error {
spi.Bus.CR.Set(nxp.LPSPI_CR_MEN) spi.Bus.CR.Set(nxp.LPSPI_CR_MEN)
spi.configured = true spi.configured = true
return nil
} }
// Transfer writes/reads a single byte using the SPI interface. // Transfer writes/reads a single byte using the SPI interface.
+6 -46
View File
@@ -12,34 +12,6 @@ import (
const deviceName = nrf.Device const deviceName = nrf.Device
var deviceID [8]byte
// DeviceID returns an identifier that is unique within
// a particular chipset.
//
// The identity is one burnt into the MCU itself, or the
// flash chip at time of manufacture.
//
// It's possible that two different vendors may allocate
// the same DeviceID, so callers should take this into
// account if needing to generate a globally unique id.
//
// The length of the hardware ID is vendor-specific, but
// 8 bytes (64 bits) is common.
func DeviceID() []byte {
words := make([]uint32, 2)
words[0] = nrf.FICR.DEVICEID[0].Get()
words[1] = nrf.FICR.DEVICEID[1].Get()
for i := 0; i < 8; i++ {
shift := (i % 4) * 8
w := i / 4
deviceID[i] = byte(words[w] >> shift)
}
return deviceID[:]
}
const ( const (
PinInput PinMode = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) PinInput PinMode = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos)
PinInputPullup PinMode = PinInput | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) PinInputPullup PinMode = PinInput | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos)
@@ -274,8 +246,13 @@ func (i2c *I2C) Configure(config I2CConfig) error {
i2c.setPins(config.SCL, config.SDA) i2c.setPins(config.SCL, config.SDA)
i2c.mode = config.Mode i2c.mode = config.Mode
if i2c.mode == I2CModeController { if i2c.mode == I2CModeController {
i2c.SetBaudRate(config.Frequency) if config.Frequency >= 400*KHz {
i2c.Bus.FREQUENCY.Set(nrf.TWI_FREQUENCY_FREQUENCY_K400)
} else {
i2c.Bus.FREQUENCY.Set(nrf.TWI_FREQUENCY_FREQUENCY_K100)
}
i2c.enableAsController() i2c.enableAsController()
} else { } else {
@@ -285,23 +262,6 @@ func (i2c *I2C) Configure(config I2CConfig) error {
return nil return nil
} }
// SetBaudRate sets the I2C frequency. It has the side effect of also
// enabling the I2C hardware if disabled beforehand.
//
//go:inline
func (i2c *I2C) SetBaudRate(br uint32) error {
switch {
case br >= 400*KHz:
i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K400)
case br >= 250*KHz:
i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K250)
default:
i2c.Bus.SetFREQUENCY(nrf.TWI_FREQUENCY_FREQUENCY_K100)
}
return nil
}
// signalStop sends a stop signal to the I2C peripheral and waits for confirmation. // signalStop sends a stop signal to the I2C peripheral and waits for confirmation.
func (i2c *I2C) signalStop() error { func (i2c *I2C) signalStop() error {
tries := 0 tries := 0
+1 -3
View File
@@ -49,7 +49,7 @@ type SPIConfig struct {
} }
// Configure is intended to setup the SPI interface. // Configure is intended to setup the SPI interface.
func (spi SPI) Configure(config SPIConfig) error { func (spi SPI) Configure(config SPIConfig) {
// Disable bus to configure it // Disable bus to configure it
spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Disabled) spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Disabled)
@@ -117,8 +117,6 @@ func (spi SPI) Configure(config SPIConfig) error {
// Re-enable bus now that it is configured. // Re-enable bus now that it is configured.
spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Enabled) spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Enabled)
return nil
} }
// Transfer writes/reads a single byte using the SPI interface. // Transfer writes/reads a single byte using the SPI interface.
+1 -3
View File
@@ -197,7 +197,7 @@ type SPIConfig struct {
} }
// Configure is intended to setup the SPI interface. // Configure is intended to setup the SPI interface.
func (spi SPI) Configure(config SPIConfig) error { func (spi SPI) Configure(config SPIConfig) {
// Disable bus to configure it // Disable bus to configure it
spi.Bus.ENABLE.Set(nrf.SPIM_ENABLE_ENABLE_Disabled) spi.Bus.ENABLE.Set(nrf.SPIM_ENABLE_ENABLE_Disabled)
@@ -265,8 +265,6 @@ func (spi SPI) Configure(config SPIConfig) error {
// Re-enable bus now that it is configured. // Re-enable bus now that it is configured.
spi.Bus.ENABLE.Set(nrf.SPIM_ENABLE_ENABLE_Enabled) spi.Bus.ENABLE.Set(nrf.SPIM_ENABLE_ENABLE_Enabled)
return nil
} }
// Transfer writes/reads a single byte using the SPI interface. // Transfer writes/reads a single byte using the SPI interface.
-26
View File
@@ -13,32 +13,6 @@ func EnterBootloader() {
enterBootloader() enterBootloader()
} }
// 13 = 1 + FLASH_RUID_DUMMY_BYTES(4) + FLASH_RUID_DATA_BYTES(8)
var deviceIDBuf [13]byte
// DeviceID returns an identifier that is unique within
// a particular chipset.
//
// The identity is one burnt into the MCU itself, or the
// flash chip at time of manufacture.
//
// It's possible that two different vendors may allocate
// the same DeviceID, so callers should take this into
// account if needing to generate a globally unique id.
//
// The length of the hardware ID is vendor-specific, but
// 8 bytes (64 bits) is common.
func DeviceID() []byte {
deviceIDBuf[0] = 0x4b // FLASH_RUID_CMD
err := doFlashCommand(deviceIDBuf[:], deviceIDBuf[:])
if err != nil {
panic(err)
}
return deviceIDBuf[5:13]
}
// compile-time check for ensuring we fulfill BlockDevice interface // compile-time check for ensuring we fulfill BlockDevice interface
var _ BlockDevice = flashBlockDevice{} var _ BlockDevice = flashBlockDevice{}
-76
View File
@@ -93,33 +93,6 @@ static ram_func void flash_enable_xip_via_boot2() {
((void (*)(void))boot2_copyout+1)(); ((void (*)(void))boot2_copyout+1)();
} }
#define IO_QSPI_BASE 0x40018000
#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS 0x00000300
#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_MSB 9
#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB 8
#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW 0x2
#define IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH 0x3
#define XIP_SSI_BASE 0x18000000
#define ssi_hw ((ssi_hw_t *)XIP_SSI_BASE)
#define SSI_SR_OFFSET 0x00000028
#define SSI_DR0_OFFSET 0x00000060
#define SSI_SR_TFNF_BITS 0x00000002
#define SSI_SR_RFNE_BITS 0x00000008
void ram_func flash_cs_force(bool high) {
uint32_t field_val = high ?
IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_HIGH :
IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_VALUE_LOW;
// &ioqspi_hw->io[1].ctrl
uint32_t *addr = (uint32_t*)(IO_QSPI_BASE + (1 * 8) + 4);
*addr = ((*addr) & !IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_BITS)
| (field_val << IO_QSPI_GPIO_QSPI_SS_CTRL_OUTOVER_LSB);
}
// See https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_flash/flash.c#L86 // See https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/hardware_flash/flash.c#L86
void ram_func flash_range_write(uint32_t offset, const uint8_t *data, size_t count) void ram_func flash_range_write(uint32_t offset, const uint8_t *data, size_t count)
{ {
@@ -159,42 +132,6 @@ void ram_func flash_erase_blocks(uint32_t offset, size_t count)
flash_enable_xip_via_boot2(); flash_enable_xip_via_boot2();
} }
void ram_func flash_do_cmd(const uint8_t *txbuf, uint8_t *rxbuf, size_t count) {
flash_connect_internal_fn flash_connect_internal_func = (flash_connect_internal_fn) rom_func_lookup(ROM_FUNC_CONNECT_INTERNAL_FLASH);
flash_exit_xip_fn flash_exit_xip_func = (flash_exit_xip_fn) rom_func_lookup(ROM_FUNC_FLASH_EXIT_XIP);
flash_flush_cache_fn flash_flush_cache_func = (flash_flush_cache_fn) rom_func_lookup(ROM_FUNC_FLASH_FLUSH_CACHE);
flash_init_boot2_copyout();
__compiler_memory_barrier();
flash_connect_internal_func();
flash_exit_xip_func();
flash_cs_force(0);
size_t tx_remaining = count;
size_t rx_remaining = count;
// We may be interrupted -- don't want FIFO to overflow if we're distracted.
const size_t max_in_flight = 16 - 2;
while (tx_remaining || rx_remaining) {
uint32_t flags = *(uint32_t*)(XIP_SSI_BASE + SSI_SR_OFFSET);
bool can_put = !!(flags & SSI_SR_TFNF_BITS);
bool can_get = !!(flags & SSI_SR_RFNE_BITS);
if (can_put && tx_remaining && rx_remaining - tx_remaining < max_in_flight) {
*(uint32_t*)(XIP_SSI_BASE + SSI_DR0_OFFSET) = *txbuf++;
--tx_remaining;
}
if (can_get && rx_remaining) {
*rxbuf++ = (uint8_t)*(uint32_t*)(XIP_SSI_BASE + SSI_DR0_OFFSET);
--rx_remaining;
}
}
flash_cs_force(1);
flash_flush_cache_func();
flash_enable_xip_via_boot2();
}
*/ */
import "C" import "C"
@@ -202,19 +139,6 @@ func enterBootloader() {
C.reset_usb_boot(0, 0) C.reset_usb_boot(0, 0)
} }
func doFlashCommand(tx []byte, rx []byte) error {
if len(tx) != len(rx) {
return errFlashInvalidWriteLength
}
C.flash_do_cmd(
(*C.uint8_t)(unsafe.Pointer(&tx[0])),
(*C.uint8_t)(unsafe.Pointer(&rx[0])),
C.ulong(len(tx)))
return nil
}
// Flash related code // Flash related code
const memoryStart = C.XIP_BASE // memory start for purpose of erase const memoryStart = C.XIP_BASE // memory start for purpose of erase
+1 -42
View File
@@ -289,26 +289,7 @@ func (spi SPI) isBusy() bool {
// tx writes buffer to SPI ignoring Rx. // tx writes buffer to SPI ignoring Rx.
func (spi SPI) tx(tx []byte) error { func (spi SPI) tx(tx []byte) error {
err := spi.StartTx(tx, nil) if len(tx) == 0 {
if err != nil {
return err
}
return spi.Wait()
}
// IsAsync returns whether the SPI supports async operation (usually DMA).
//
// It returns true on the rp2040.
func (spi SPI) IsAsync() bool {
return true
}
// Start a transfer in the background.
//
// After this, another StartTx() or Wait() must be called. The provided byte
// slices (tx and rx) may only be accessed again after Wait() was called.
func (spi SPI) StartTx(tx, rx []byte) error {
if len(tx) == 0 && len(rx) == 0 {
// We don't have to do anything. // We don't have to do anything.
// This avoids a panic in &tx[0] when len(tx) == 0. // This avoids a panic in &tx[0] when len(tx) == 0.
return nil return nil
@@ -325,15 +306,6 @@ func (spi SPI) StartTx(tx, rx []byte) error {
dreq = 18 // DREQ_SPI1_TX dreq = 18 // DREQ_SPI1_TX
} }
// Wait for the previous transmission to complete.
for ch.CTRL_TRIG.Get()&rp.DMA_CH0_CTRL_TRIG_BUSY != 0 {
}
if len(rx) != 0 {
// Fallback. We don't support receiving data using DMA yet.
return spi.Tx(tx, rx)
}
// Configure the DMA peripheral as follows: // Configure the DMA peripheral as follows:
// - set read address, write address, and number of transfer units (bytes) // - set read address, write address, and number of transfer units (bytes)
// - increment read address (in memory), don't increment write address (SSPDR) // - increment read address (in memory), don't increment write address (SSPDR)
@@ -347,19 +319,6 @@ func (spi SPI) StartTx(tx, rx []byte) error {
rp.DMA_CH0_CTRL_TRIG_DATA_SIZE_SIZE_BYTE<<rp.DMA_CH0_CTRL_TRIG_DATA_SIZE_Pos | rp.DMA_CH0_CTRL_TRIG_DATA_SIZE_SIZE_BYTE<<rp.DMA_CH0_CTRL_TRIG_DATA_SIZE_Pos |
dreq<<rp.DMA_CH0_CTRL_TRIG_TREQ_SEL_Pos | dreq<<rp.DMA_CH0_CTRL_TRIG_TREQ_SEL_Pos |
rp.DMA_CH0_CTRL_TRIG_EN) rp.DMA_CH0_CTRL_TRIG_EN)
return nil
}
// Wait until all active transactions (started by StartTx) have finished. The
// buffers provided in StartTx will be available after this method returns.
func (spi SPI) Wait() error {
// Pick the DMA channel reserved for this SPI peripheral.
var ch *dmaChannel
if spi.Bus == rp.SPI0 {
ch = &dmaChannels[spi0DMAChannel]
} else { // SPI1
ch = &dmaChannels[spi1DMAChannel]
}
// Wait until the transfer is complete. // Wait until the transfer is complete.
// TODO: do this more efficiently: // TODO: do this more efficiently:
+1 -23
View File
@@ -2,12 +2,7 @@
package machine package machine
import ( import "device/stm32"
"device/stm32"
"runtime/volatile"
"unsafe"
)
const deviceName = stm32.Device const deviceName = stm32.Device
@@ -85,20 +80,3 @@ func (p Pin) PortMaskClear() (*uint32, uint32) {
pin := uint8(p) % 16 pin := uint8(p) % 16
return &port.BSRR.Reg, 1 << (pin + 16) return &port.BSRR.Reg, 1 << (pin + 16)
} }
var deviceID [12]byte
// DeviceID returns an identifier that is unique within
// a particular chipset.
//
// The identity is one burnt into the MCU itself.
//
// The length of the device ID for STM32 is 12 bytes (96 bits).
func DeviceID() []byte {
for i := 0; i < len(deviceID); i++ {
word := (*volatile.Register32)(unsafe.Pointer(deviceIDAddr[i/4])).Get()
deviceID[i] = byte(word >> ((i % 4) * 8))
}
return deviceID[:]
}
-6
View File
@@ -157,12 +157,6 @@ func (i2c *I2C) Configure(config I2CConfig) error {
return nil return nil
} }
// SetBaudRate sets the communication speed for I2C.
func (i2c *I2C) SetBaudRate(br uint32) error {
// TODO: implement
return errI2CNotImplemented
}
func (i2c *I2C) Tx(addr uint16, w, r []byte) error { func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
if err := i2c.controllerTransmit(addr, w); nil != err { if err := i2c.controllerTransmit(addr, w); nil != err {
-6
View File
@@ -84,12 +84,6 @@ func (i2c *I2C) Configure(config I2CConfig) error {
return nil return nil
} }
// SetBaudRate sets the communication speed for I2C.
func (i2c *I2C) SetBaudRate(br uint32) error {
// TODO: implement
return errI2CNotImplemented
}
func (i2c *I2C) Tx(addr uint16, w, r []byte) error { func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
if len(w) > 0 { if len(w) > 0 {
if err := i2c.controllerTransmit(addr, w); nil != err { if err := i2c.controllerTransmit(addr, w); nil != err {
+1 -3
View File
@@ -21,7 +21,7 @@ type SPIConfig struct {
} }
// Configure is intended to setup the STM32 SPI1 interface. // Configure is intended to setup the STM32 SPI1 interface.
func (spi SPI) Configure(config SPIConfig) error { func (spi SPI) Configure(config SPIConfig) {
// -- CONFIGURING THE SPI IN MASTER MODE -- // -- CONFIGURING THE SPI IN MASTER MODE --
// //
@@ -93,8 +93,6 @@ func (spi SPI) Configure(config SPIConfig) error {
// enable SPI // enable SPI
spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE) spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE)
return nil
} }
// Transfer writes/reads a single byte using the SPI interface. // Transfer writes/reads a single byte using the SPI interface.
-2
View File
@@ -15,8 +15,6 @@ func CPUFrequency() uint32 {
return 72000000 return 72000000
} }
var deviceIDAddr = []uintptr{0x1FFFF7E8, 0x1FFFF7EC, 0x1FFFF7F0}
// Internal use: configured speed of the APB1 and APB2 timers, this should be kept // Internal use: configured speed of the APB1 and APB2 timers, this should be kept
// in sync with any changes to runtime package which configures the oscillators // in sync with any changes to runtime package which configures the oscillators
// and clock frequencies // and clock frequencies
-2
View File
@@ -14,8 +14,6 @@ import (
"unsafe" "unsafe"
) )
var deviceIDAddr = []uintptr{0x1FFF7A10, 0x1FFF7A14, 0x1FFF7A18}
const ( const (
PA0 = portA + 0 PA0 = portA + 0
PA1 = portA + 1 PA1 = portA + 1
-2
View File
@@ -11,8 +11,6 @@ import (
"unsafe" "unsafe"
) )
var deviceIDAddr = []uintptr{0x1FF0F420, 0x1FF0F424, 0x1FF0F428}
// Alternative peripheral pin functions // Alternative peripheral pin functions
const ( const (
AF0_SYSTEM = 0 AF0_SYSTEM = 0
-2
View File
@@ -13,8 +13,6 @@ func CPUFrequency() uint32 {
return 32000000 return 32000000
} }
var deviceIDAddr = []uintptr{0x1FF80050, 0x1FF80054, 0x1FF80058}
// Internal use: configured speed of the APB1 and APB2 timers, this should be kept // Internal use: configured speed of the APB1 and APB2 timers, this should be kept
// in sync with any changes to runtime package which configures the oscillators // in sync with any changes to runtime package which configures the oscillators
// and clock frequencies // and clock frequencies
-2
View File
@@ -13,8 +13,6 @@ import (
// Peripheral abstraction layer for the stm32l4 // Peripheral abstraction layer for the stm32l4
var deviceIDAddr = []uintptr{0x1FFF7590, 0x1FFF7594, 0x1FFF7598}
const ( const (
AF0_SYSTEM = 0 AF0_SYSTEM = 0
AF1_TIM1_2_LPTIM1 = 1 AF1_TIM1_2_LPTIM1 = 1
-2
View File
@@ -11,8 +11,6 @@ import (
"unsafe" "unsafe"
) )
var deviceIDAddr = []uintptr{0x0BFA0590, 0x0BFA0594, 0x0BFA0598}
const ( const (
AF0_SYSTEM = 0 AF0_SYSTEM = 0
AF1_TIM1_2_5_8_LPTIM1 = 1 AF1_TIM1_2_5_8_LPTIM1 = 1
-2
View File
@@ -14,8 +14,6 @@ import (
"unsafe" "unsafe"
) )
var deviceIDAddr = []uintptr{0x1FFF7590, 0x1FFF7594, 0x1FFF7598}
const ( const (
AF0_SYSTEM = 0 AF0_SYSTEM = 0
AF1_TIM1_2_LPTIM1 = 1 AF1_TIM1_2_LPTIM1 = 1
-29
View File
@@ -1,29 +0,0 @@
//go:build !baremetal || atmega || esp32 || fe310 || k210 || nrf || (nxp && !mk66f18) || atsamd21 || (stm32 && !stm32f7x2 && !stm32l5x2)
package machine
// This is a non-async implementation of the async SPI calls.
// It is useful for devices that don't support DMA on SPI, or for which it
// hasn't been implemented yet.
// IsAsync returns whether the SPI supports async operation (usually DMA).
//
// This SPI does not support async operations.
func (s SPI) IsAsync() bool {
return false
}
// Start a transfer in the background.
//
// Because this SPI implementation doesn't support async operation, it is an
// alias for Tx.
func (s SPI) StartTx(tx, rx []byte) error {
return s.Tx(tx, rx)
}
// Wait until all active transactions (started by StartTx) have finished.
//
// This is a no-op on this SPI implementation.
func (s SPI) Wait() error {
return nil
}
-14
View File
@@ -16,17 +16,3 @@ var (
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size") ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
errSPIInvalidMachineConfig = errors.New("SPI port was not configured properly by the machine") errSPIInvalidMachineConfig = errors.New("SPI port was not configured properly by the machine")
) )
// If you are getting a compile error on this line please check to see you've
// correctly implemented the methods on the SPI type. They must match
// the interface method signatures type to type perfectly.
// If not implementing the SPI type please remove your target from the build tags
// at the top of this file.
var _ interface { // 2
Configure(config SPIConfig) error
Tx(w, r []byte) error
Transfer(w byte) (byte, error)
IsAsync() bool
StartTx(tx, rx []byte) error
Wait() error
} = (*SPI)(nil)
+2 -1
View File
@@ -10,7 +10,8 @@ func Callers(skip int, pc []uintptr) int {
var buildVersion string var buildVersion string
// Version returns the Tinygo tree's version string. // Version returns the Tinygo tree's version string.
// It is the same as goenv.Version(). // It is the same as goenv.Version, or in case of a development build,
// it will be the concatenation of goenv.Version and the git commit hash.
func Version() string { func Version() string {
return buildVersion return buildVersion
} }
+5 -5
View File
@@ -17,11 +17,11 @@
// //
// | object type | size | bitstring | note // | object type | size | bitstring | note
// |-------------|------|-----------|------ // |-------------|------|-----------|------
// | int | 1 | 0 | no pointers in this object // | int | 1 | 0 | no pointers in this object
// | string | 2 | 01 | {pointer, len} pair so there is one pointer // | string | 2 | 10 | {pointer, len} pair so there is one pointer
// | []int | 3 | 001 | {pointer, len, cap} // | []int | 3 | 100 | {pointer, len, cap}
// | [4]*int | 1 | 1 | even though it contains 4 pointers, an array repeats so it can be stored with size=1 // | [4]*int | 1 | 1 | even though it contains 4 pointers, an array repeats so it can be stored with size=1
// | [30]byte | 1 | 0 | there are no pointers so the layout is very simple // | [30]byte | 1 | 0 | there are no pointers so the layout is very simple
// //
// The garbage collector scans objects by starting at the first word value in // The garbage collector scans objects by starting at the first word value in
// the object. If the least significant bit of the bitstring is clear, it is // the object. If the least significant bit of the bitstring is clear, it is
+2 -2
View File
@@ -9,7 +9,7 @@
"libc": "wasi-libc", "libc": "wasi-libc",
"rtlib": "compiler-rt", "rtlib": "compiler-rt",
"scheduler": "asyncify", "scheduler": "asyncify",
"default-stack-size": 65536, "default-stack-size": 32768,
"cflags": [ "cflags": [
"-mbulk-memory", "-mbulk-memory",
"-mnontrapping-fptoint", "-mnontrapping-fptoint",
@@ -22,5 +22,5 @@
"extra-files": [ "extra-files": [
"src/runtime/asm_tinygowasm.S" "src/runtime/asm_tinygowasm.S"
], ],
"emulator": "wasmtime --dir={tmpDir}::/tmp {}" "emulator": "wasmtime --mapdir=/tmp::{tmpDir} {}"
} }
+1 -1
View File
@@ -9,7 +9,7 @@
"libc": "wasi-libc", "libc": "wasi-libc",
"rtlib": "compiler-rt", "rtlib": "compiler-rt",
"scheduler": "asyncify", "scheduler": "asyncify",
"default-stack-size": 65536, "default-stack-size": 32768,
"cflags": [ "cflags": [
"-mbulk-memory", "-mbulk-memory",
"-mnontrapping-fptoint", "-mnontrapping-fptoint",
+65 -21
View File
@@ -10,9 +10,11 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"runtime"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
"sync"
"text/template" "text/template"
"unicode" "unicode"
) )
@@ -1441,6 +1443,31 @@ __isr_vector:
return w.Flush() return w.Flush()
} }
// Process a single SVD file, synchronously.
func processFile(infile, outdir, sourceURL, interruptSystem string) error {
device, err := readSVD(infile, sourceURL)
if err != nil {
return fmt.Errorf("failed to read: %w", err)
}
err = writeGo(outdir, device, interruptSystem)
if err != nil {
return fmt.Errorf("failed to write Go file: %w", err)
}
switch interruptSystem {
case "software":
// Nothing to do.
case "hardware":
err = writeAsm(outdir, device)
if err != nil {
return fmt.Errorf("failed to write assembly file: %w", err)
}
default:
return fmt.Errorf("unknown interrupt system: %s", interruptSystem)
}
return nil
}
// Process an entire directory, in parallel.
func generate(indir, outdir, sourceURL, interruptSystem string) error { func generate(indir, outdir, sourceURL, interruptSystem string) error {
if _, err := os.Stat(indir); errors.Is(err, fs.ErrNotExist) { if _, err := os.Stat(indir); errors.Is(err, fs.ErrNotExist) {
fmt.Fprintln(os.Stderr, "cannot find input directory:", indir) fmt.Fprintln(os.Stderr, "cannot find input directory:", indir)
@@ -1448,35 +1475,52 @@ func generate(indir, outdir, sourceURL, interruptSystem string) error {
} }
os.MkdirAll(outdir, 0777) os.MkdirAll(outdir, 0777)
// Read list of SVD files to process.
infiles, err := filepath.Glob(filepath.Join(indir, "*.svd")) infiles, err := filepath.Glob(filepath.Join(indir, "*.svd"))
if err != nil { if err != nil {
fmt.Fprintln(os.Stderr, "could not read .svd files:", err) fmt.Fprintln(os.Stderr, "could not read .svd files:", err)
os.Exit(1) os.Exit(1)
} }
sort.Strings(infiles) sort.Strings(infiles)
for _, infile := range infiles {
fmt.Println(infile) // Start worker goroutines.
device, err := readSVD(infile, sourceURL) var wg sync.WaitGroup
if err != nil { workChan := make(chan string)
return fmt.Errorf("failed to read: %w", err) errChan := make(chan error, 1)
} for i := 0; i < runtime.NumCPU(); i++ {
err = writeGo(outdir, device, interruptSystem) go func() {
if err != nil { for infile := range workChan {
return fmt.Errorf("failed to write Go file: %w", err) err := processFile(infile, outdir, sourceURL, interruptSystem)
} if err != nil {
switch interruptSystem { // Store error to errChan if no error was stored before.
case "software": select {
// Nothing to do. case errChan <- err:
case "hardware": default:
err = writeAsm(outdir, device) }
if err != nil { }
return fmt.Errorf("failed to write assembly file: %w", err) wg.Done()
} }
default: }()
return fmt.Errorf("unknown interrupt system: %s", interruptSystem) }
}
// Submit all jobs to the goroutines.
wg.Add(len(infiles))
for _, filepath := range infiles {
fmt.Println(filepath)
workChan <- filepath
}
close(workChan)
// Wait until all workers have finished.
wg.Wait()
// Check for an error.
select {
case err := <-errChan:
return err
default:
return nil
} }
return nil
} }
func main() { func main() {
+1 -1
View File
@@ -145,7 +145,7 @@ func compileGoFileForTesting(t *testing.T, filename string) llvm.Module {
defer machine.Dispose() defer machine.Dispose()
// Load entire program AST into memory. // Load entire program AST into memory.
lprogram, err := loader.Load(config, filename, types.Config{ lprogram, err := loader.Load(config, filename, config.ClangHeaders, types.Config{
Sizes: compiler.Sizes(machine), Sizes: compiler.Sizes(machine),
}) })
if err != nil { if err != nil {