mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 19:17:47 +00:00
Compare commits
69 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cf0b7edc78 | |||
| a32cda7a4c | |||
| b251ce7b33 | |||
| 1abe1203a3 | |||
| 8b360ec911 | |||
| 93654544b3 | |||
| 050d516264 | |||
| 9a8328fcb7 | |||
| 6812a4dc04 | |||
| 8568d4f625 | |||
| bd56636d58 | |||
| 4fe3a379a5 | |||
| fce42fc7fa | |||
| 5d177d1328 | |||
| 9eb4a6268a | |||
| 11a402de95 | |||
| cdd9198888 | |||
| 6055e6eb23 | |||
| 9239c61edb | |||
| 008b373df4 | |||
| c387a09f54 | |||
| 5bb3ca2618 | |||
| a4ea85b303 | |||
| 27d38a9663 | |||
| ee497a296b | |||
| 6b31ee1e93 | |||
| cad6a57077 | |||
| 52233790cc | |||
| 9160f3f16d | |||
| 69d7ed5cda | |||
| 111661658b | |||
| 3000b2d15e | |||
| c89f026532 | |||
| e09b1d06f5 | |||
| 0590ccb260 | |||
| fe0acb1670 | |||
| d58c7d2521 | |||
| 85f5411d60 | |||
| c5de68622e | |||
| 8fb93fbac4 | |||
| ef3b3c0d6a | |||
| 2dc46a851b | |||
| f3afc7bbf3 | |||
| 4858b27120 | |||
| 7f507a7026 | |||
| 83227e68df | |||
| 09a3c6a16b | |||
| f613cb41a3 | |||
| e060e588ab | |||
| 8dfb317d28 | |||
| 9cedd78d9c | |||
| 20a27746b2 | |||
| c78df85015 | |||
| c0d257d682 | |||
| 7af24c7864 | |||
| 3dc1e403ea | |||
| 1deee3ec5a | |||
| 0f9f316db2 | |||
| 0dd521e1d1 | |||
| 1dcdd5f2d2 | |||
| dcd8ee63a8 | |||
| b8bf0ac3f1 | |||
| 73571dd423 | |||
| 8872229a0b | |||
| 7e05efa274 | |||
| b02cea0321 | |||
| 8823a934a3 | |||
| 6ac02cc34c | |||
| e259598b68 |
@@ -22,15 +22,16 @@ commands:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- llvm-source-13-v1
|
||||
- llvm-source-14-v1
|
||||
- run:
|
||||
name: "Fetch LLVM source"
|
||||
command: make llvm-source
|
||||
- save_cache:
|
||||
key: llvm-source-13-v1
|
||||
key: llvm-source-14-v1
|
||||
paths:
|
||||
- llvm-project/clang/lib/Headers
|
||||
- llvm-project/clang/include
|
||||
- llvm-project/compiler-rt
|
||||
- llvm-project/lld/include
|
||||
- llvm-project/llvm/include
|
||||
hack-ninja-jobs:
|
||||
@@ -85,10 +86,10 @@ commands:
|
||||
- run: go install -tags=llvm<<parameters.llvm>> .
|
||||
- restore_cache:
|
||||
keys:
|
||||
- wasi-libc-sysroot-systemclang-v4
|
||||
- wasi-libc-sysroot-systemclang-v5
|
||||
- run: make wasi-libc
|
||||
- save_cache:
|
||||
key: wasi-libc-sysroot-systemclang-v4
|
||||
key: wasi-libc-sysroot-systemclang-v5
|
||||
paths:
|
||||
- lib/wasi-libc/sysroot
|
||||
- run: make gen-device -j4
|
||||
@@ -107,9 +108,9 @@ jobs:
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "11"
|
||||
test-llvm12-go116:
|
||||
test-llvm12-go117:
|
||||
docker:
|
||||
- image: circleci/golang:1.16-buster
|
||||
- image: circleci/golang:1.17-buster
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "12"
|
||||
@@ -118,4 +119,4 @@ workflows:
|
||||
test-all:
|
||||
jobs:
|
||||
- test-llvm11-go115
|
||||
- test-llvm12-go116
|
||||
- test-llvm12-go117
|
||||
|
||||
@@ -10,12 +10,12 @@ on:
|
||||
jobs:
|
||||
build-macos:
|
||||
name: build-macos
|
||||
runs-on: macos-10.15
|
||||
runs-on: macos-11
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18.1'
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
@@ -35,10 +35,11 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-13-macos-v1
|
||||
key: llvm-source-14-macos-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
llvm-project/compiler-rt
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Download LLVM source
|
||||
@@ -48,7 +49,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-13-macos-v3
|
||||
key: llvm-build-14-macos-v1
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -66,7 +67,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-v2
|
||||
key: wasi-libc-sysroot-v3
|
||||
path: lib/wasi-libc/sysroot
|
||||
- name: Build wasi-libc
|
||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||
|
||||
+118
-12
@@ -26,7 +26,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18.1'
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
@@ -38,10 +38,11 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-13-linux-v1
|
||||
key: llvm-source-14-linux-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
llvm-project/compiler-rt
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Download LLVM source
|
||||
@@ -51,7 +52,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-13-linux-v2
|
||||
key: llvm-build-14-linux-v1
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -76,14 +77,13 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-linux-asserts-v3
|
||||
key: wasi-libc-sysroot-linux-asserts-v4
|
||||
path: lib/wasi-libc/sysroot
|
||||
- name: Build wasi-libc
|
||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||
run: make wasi-libc
|
||||
- name: Install fpm
|
||||
run: |
|
||||
sudo apt-get install ruby ruby-dev
|
||||
sudo gem install --no-document fpm
|
||||
- name: Build TinyGo release
|
||||
run: |
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
- name: Publish release artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: release-double-zipped
|
||||
name: linux-amd64-double-zipped
|
||||
path: |
|
||||
/tmp/tinygo.linux-amd64.tar.gz
|
||||
/tmp/tinygo_amd64.deb
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18.1'
|
||||
- name: Install wasmtime
|
||||
run: |
|
||||
curl https://wasmtime.dev/install.sh -sSf | bash
|
||||
@@ -115,7 +115,7 @@ jobs:
|
||||
- name: Download release artifact
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: release-double-zipped
|
||||
name: linux-amd64-double-zipped
|
||||
- name: Extract release tarball
|
||||
run: |
|
||||
mkdir -p ~/lib
|
||||
@@ -159,7 +159,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18.1'
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
@@ -179,10 +179,11 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-13-linux-asserts-v1
|
||||
key: llvm-source-14-linux-asserts-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
llvm-project/compiler-rt
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Download LLVM source
|
||||
@@ -192,7 +193,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-13-linux-asserts-v2
|
||||
key: llvm-build-14-linux-asserts-v1
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -217,7 +218,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-linux-asserts-v3
|
||||
key: wasi-libc-sysroot-linux-asserts-v4
|
||||
path: lib/wasi-libc/sysroot
|
||||
- name: Build wasi-libc
|
||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||
@@ -240,3 +241,108 @@ jobs:
|
||||
- run: make smoketest
|
||||
- run: make wasmtest
|
||||
- run: make tinygo-baremetal
|
||||
build-linux-arm:
|
||||
# Build ARM Linux binaries, ready for release.
|
||||
# This intentionally uses an older Linux image, so that we compile against
|
||||
# an older glibc version and therefore are compatible with a wide range of
|
||||
# Linux distributions.
|
||||
# It is set to "needs: build-linux" because it modifies the release created
|
||||
# in that process to avoid doing lots of duplicate work and to avoid
|
||||
# complications around precompiled libraries such as compiler-rt shipped as
|
||||
# part of the release tarball.
|
||||
runs-on: ubuntu-18.04
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Install apt dependencies
|
||||
run: |
|
||||
sudo apt-get install --no-install-recommends \
|
||||
qemu-user \
|
||||
g++-arm-linux-gnueabihf \
|
||||
libc6-dev-armhf-cross
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17'
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
key: go-cache-linux-arm-v2-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
- name: Cache LLVM source
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-14-linux-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
llvm-project/compiler-rt
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Download LLVM source
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache LLVM build
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-14-linux-arm-v1
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
# fetch LLVM source
|
||||
rm -rf llvm-project
|
||||
make llvm-source
|
||||
# Install build dependencies.
|
||||
sudo apt-get install --no-install-recommends ninja-build
|
||||
# build!
|
||||
make llvm-build CROSS=arm-linux-gnueabihf
|
||||
# Remove unnecessary object files (to reduce cache size).
|
||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||
- name: Cache Binaryen
|
||||
uses: actions/cache@v2
|
||||
id: cache-binaryen
|
||||
with:
|
||||
key: binaryen-linux-arm-v1
|
||||
path: build/wasm-opt
|
||||
- name: Build Binaryen
|
||||
if: steps.cache-binaryen.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
sudo apt-get install --no-install-recommends ninja-build
|
||||
git submodule update --init lib/binaryen
|
||||
make CROSS=arm-linux-gnueabihf binaryen
|
||||
- name: Install fpm
|
||||
run: |
|
||||
sudo gem install --no-document fpm
|
||||
- name: Build TinyGo binary
|
||||
run: |
|
||||
make CROSS=arm-linux-gnueabihf
|
||||
- name: Download amd64 release
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: linux-amd64-double-zipped
|
||||
- name: Extract amd64 release
|
||||
run: |
|
||||
mkdir -p build/release
|
||||
tar -xf tinygo.linux-amd64.tar.gz -C build/release tinygo
|
||||
- name: Modify release
|
||||
run: |
|
||||
cp -p build/tinygo build/release/tinygo/bin
|
||||
cp -p build/wasm-opt build/release/tinygo/bin
|
||||
- name: Create arm release
|
||||
run: |
|
||||
make release deb RELEASEONLY=1 DEB_ARCH=armhf
|
||||
cp -p build/release.tar.gz /tmp/tinygo.linux-arm.tar.gz
|
||||
cp -p build/release.deb /tmp/tinygo_armhf.deb
|
||||
- name: Publish release artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: linux-arm-double-zipped
|
||||
path: |
|
||||
/tmp/tinygo.linux-arm.tar.gz
|
||||
/tmp/tinygo_armhf.deb
|
||||
|
||||
@@ -9,12 +9,12 @@ on:
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
runs-on: windows-2019
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: '1.17'
|
||||
go-version: '1.18.1'
|
||||
- uses: brechtm/setup-scoop@v2
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
@@ -35,10 +35,11 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-13-windows-v1
|
||||
key: llvm-source-14-windows-v1
|
||||
path: |
|
||||
llvm-project/clang/lib/Headers
|
||||
llvm-project/clang/include
|
||||
llvm-project/compiler-rt
|
||||
llvm-project/lld/include
|
||||
llvm-project/llvm/include
|
||||
- name: Download LLVM source
|
||||
@@ -48,7 +49,7 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-13-windows-v2
|
||||
key: llvm-build-14-windows-v1
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
@@ -65,11 +66,14 @@ jobs:
|
||||
uses: actions/cache@v2
|
||||
id: cache-wasi-libc
|
||||
with:
|
||||
key: wasi-libc-sysroot-v2
|
||||
key: wasi-libc-sysroot-v3
|
||||
path: lib/wasi-libc/sysroot
|
||||
- name: Build wasi-libc
|
||||
if: steps.cache-wasi-libc.outputs.cache-hit != 'true'
|
||||
run: make wasi-libc
|
||||
- name: Install wasmtime
|
||||
run: |
|
||||
scoop install wasmtime
|
||||
- name: Test TinyGo
|
||||
shell: bash
|
||||
run: make test GOTESTFLAGS="-v -short"
|
||||
@@ -95,3 +99,5 @@ jobs:
|
||||
run: make smoketest TINYGO=$(PWD)/build/tinygo AVR=0 XTENSA=0
|
||||
- name: Test stdlib packages
|
||||
run: make tinygo-test
|
||||
- name: Test stdlib packages on wasi
|
||||
run: make tinygo-test-wasi-fast
|
||||
|
||||
@@ -10,10 +10,6 @@
|
||||
[submodule "lib/cmsis-svd"]
|
||||
path = lib/cmsis-svd
|
||||
url = https://github.com/tinygo-org/cmsis-svd
|
||||
[submodule "lib/compiler-rt"]
|
||||
path = lib/compiler-rt
|
||||
url = https://github.com/llvm-mirror/compiler-rt.git
|
||||
branch = release_80
|
||||
[submodule "lib/wasi-libc"]
|
||||
path = lib/wasi-libc
|
||||
url = https://github.com/CraneStation/wasi-libc
|
||||
|
||||
@@ -1,3 +1,101 @@
|
||||
0.23.0
|
||||
---
|
||||
|
||||
* **command line**
|
||||
- add `-work` flag
|
||||
- add Go 1.18 support
|
||||
- add LLVM 14 support
|
||||
- `run`: add support for command-line parameters
|
||||
- `build`: calculate default output path if `-o` is not specified
|
||||
- `build`: add JSON output
|
||||
- `test`: support multiple test binaries with `-c`
|
||||
- `test`: support flags like `-v` on all targets (including emulated firmware)
|
||||
* **compiler**
|
||||
- add support for ThinLTO
|
||||
- use compiler-rt from LLVM
|
||||
- `builder`: prefer GNU build ID over Go build ID for caching
|
||||
- `builder`: add support for cross compiling to Darwin
|
||||
- `builder`: support machine outlining pass in stacksize calculation
|
||||
- `builder`: disable asynchronous unwind tables
|
||||
- `compileopts`: fix emulator configuration on non-amd64 Linux architectures
|
||||
- `compiler`: move allocations > 256 bytes to the heap
|
||||
- `compiler`: fix incorrect `unsafe.Alignof` on some 32-bit architectures
|
||||
- `compiler`: accept alias for slice `cap` builtin
|
||||
- `compiler`: allow slices of empty structs
|
||||
- `compiler`: fix difference in aliases in interface methods
|
||||
- `compiler`: make `RawSyscall` an alias for `Syscall`
|
||||
- `compiler`: remove support for memory references in `AsmFull`
|
||||
- `loader`: only add Clang header path for CGo
|
||||
- `transform`: fix poison value in heap-to-stack transform
|
||||
* **standard library**
|
||||
- `internal/fuzz`: add this package as a shim
|
||||
- `os`: implement readdir for darwin and linux
|
||||
- `os`: add `DirFS`, which is used by many programs to access readdir.
|
||||
- `os`: isWine: be compatible with older versions of wine, too
|
||||
- `os`: implement `RemoveAll`
|
||||
- `os`: Use a `uintptr` for `NewFile`
|
||||
- `os`: add stubs for `exec.ExitError` and `ProcessState.ExitCode`
|
||||
- `os`: export correct values for `DevNull` for each OS
|
||||
- `os`: improve support for `Signal` by fixing various bugs
|
||||
- `os`: implement `File.Fd` method
|
||||
- `os`: implement `UserHomeDir`
|
||||
- `os`: add `exec.ProcessState` stub
|
||||
- `os`: implement `Pipe` for darwin
|
||||
- `os`: define stub `ErrDeadlineExceeded`
|
||||
- `reflect`: add stubs for more missing methods
|
||||
- `reflect`: rename `reflect.Ptr` to `reflect.Pointer`
|
||||
- `reflect`: add `Value.FieldByIndexErr` stub
|
||||
- `runtime`: fix various small GC bugs
|
||||
- `runtime`: use memzero for leaking collector instead of manually zeroing objects
|
||||
- `runtime`: implement `memhash`
|
||||
- `runtime`: implement `fastrand`
|
||||
- `runtime`: add stub for `debug.ReadBuildInfo`
|
||||
- `runtime`: add stub for `NumCPU`
|
||||
- `runtime`: don't inline `runtime.alloc` with `-gc=leaking`
|
||||
- `runtime`: add `Version`
|
||||
- `runtime`: add stubs for `NumCgoCall` and `NumGoroutine`
|
||||
- `runtime`: stub {Lock,Unlock}OSThread on Windows
|
||||
- `runtime`: be able to deal with a very small heap
|
||||
- `syscall`: make `Environ` return a copy of the environment
|
||||
- `syscall`: implement getpagesize and munmap
|
||||
- `syscall`: `wasi`: define `MAP_SHARED` and `PROT_READ`
|
||||
- `syscall`: stub mmap(), munmap(), MAP_SHARED, PROT_READ, SIGBUS, etc. on nonhosted targets
|
||||
- `syscall`: darwin: more complete list of signals
|
||||
- `syscall`: `wasi`: more complete list of signals
|
||||
- `syscall`: stub `WaitStatus`
|
||||
- `syscall/js`: allow copyBytesTo(Go|JS) to use `Uint8ClampedArray`
|
||||
- `testing`: implement `TempDir`
|
||||
- `testing`: nudge type TB closer to upstream; should be a no-op change.
|
||||
- `testing`: on baremetal platforms, use simpler test matcher
|
||||
* **targets**
|
||||
- `atsamd`: fix usbcdc initialization when `-serial=uart`
|
||||
- `atsamd51`: allow higher frequency when using SPI
|
||||
- `esp`: support CGo
|
||||
- `esp32c3`: add support for input pin
|
||||
- `esp32c3`: add support for GPIO interrupts
|
||||
- `esp32c3`: add support to receive UART data
|
||||
- `rp2040`: fix PWM bug at high frequency
|
||||
- `rp2040`: fix some minor I2C bugs
|
||||
- `rp2040`: fix incorrect inline assembly
|
||||
- `rp2040`: fix spurious i2c STOP during write+read transaction
|
||||
- `rp2040`: improve ADC support
|
||||
- `wasi`: remove `--export-dynamic` linker flag
|
||||
- `wasm`: remove heap allocator from wasi-libc
|
||||
* **boards**
|
||||
- `circuitplay-bluefruit`: move pin mappings so board can be compiled for WASM use in Playground
|
||||
- `esp32-c3-12f`: add the ESP32-C3-12f Kit
|
||||
- `m5stamp-c3`: add pin setting of UART
|
||||
- `macropad-rp2040`: add the Adafruit MacroPad RP2040 board
|
||||
- `nano-33-ble`: typo in LPS22HB peripheral definition and documentation (#2579)
|
||||
- `teensy41`: add the Teensy 4.1 board
|
||||
- `teensy40`: add ADC support
|
||||
- `teensy40`: add SPI support
|
||||
- `thingplus-rp2040`: add the SparkFun Thing Plus RP2040 board
|
||||
- `wioterminal`: add DefaultUART
|
||||
- `wioterminal`: verify written data when flashing through OpenOCD
|
||||
- `xiao-ble`: add XIAO BLE nRF52840 support
|
||||
|
||||
|
||||
0.22.0
|
||||
---
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||
FROM golang:1.17 AS tinygo-llvm
|
||||
FROM golang:1.18 AS tinygo-llvm
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y apt-utils make cmake clang-11 binutils-avr gcc-avr avr-libc ninja-build
|
||||
|
||||
@@ -10,7 +10,7 @@ LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
|
||||
|
||||
# Try to autodetect LLVM build tools.
|
||||
# Versions are listed here in descending priority order.
|
||||
LLVM_VERSIONS = 13 12 11
|
||||
LLVM_VERSIONS = 14 13 12 11
|
||||
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)))
|
||||
toolSearchPathsVersion = $(1)-$(2)
|
||||
@@ -50,6 +50,29 @@ else
|
||||
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
|
||||
endif
|
||||
|
||||
# Cross compiling support.
|
||||
ifneq ($(CROSS),)
|
||||
CC = $(CROSS)-gcc
|
||||
CXX = $(CROSS)-g++
|
||||
LLVM_OPTION += \
|
||||
-DCMAKE_C_COMPILER=$(CC) \
|
||||
-DCMAKE_CXX_COMPILER=$(CXX) \
|
||||
-DLLVM_DEFAULT_TARGET_TRIPLE=$(CROSS) \
|
||||
-DCROSS_TOOLCHAIN_FLAGS_NATIVE="-UCMAKE_C_COMPILER;-UCMAKE_CXX_COMPILER"
|
||||
ifeq ($(CROSS), arm-linux-gnueabihf)
|
||||
# Assume we're building on a Debian-like distro, with QEMU installed.
|
||||
LLVM_CONFIG_PREFIX = qemu-arm -L /usr/arm-linux-gnueabihf/
|
||||
# The CMAKE_SYSTEM_NAME flag triggers cross compilation mode.
|
||||
LLVM_OPTION += \
|
||||
-DCMAKE_SYSTEM_NAME=Linux \
|
||||
-DLLVM_TARGET_ARCH=ARM
|
||||
GOENVFLAGS = GOARCH=arm CC=$(CC) CXX=$(CXX) CGO_ENABLED=1
|
||||
BINARYEN_OPTION += -DCMAKE_C_COMPILER=$(CC) -DCMAKE_CXX_COMPILER=$(CXX)
|
||||
else
|
||||
$(error Unknown cross compilation target: $(CROSS))
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr gen-device-rp
|
||||
|
||||
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf debuginfopdb executionengine frontendopenmp instrumentation interpreter ipo irreader libdriver linker lto mc mcjit objcarcopts option profiledata scalaropts support target windowsmanifest
|
||||
@@ -91,11 +114,11 @@ CLANG_LIB_NAMES = clangAnalysis clangAST clangASTMatchers clangBasic clangCodeGe
|
||||
CLANG_LIBS = $(START_GROUP) $(addprefix -l,$(CLANG_LIB_NAMES)) $(END_GROUP) -lstdc++
|
||||
|
||||
# Libraries that should be linked in for the statically linked LLD.
|
||||
LLD_LIB_NAMES = lldCOFF lldCommon lldCore lldDriver lldELF lldMachO2 lldMinGW lldReaderWriter lldWasm lldYAML
|
||||
LLD_LIB_NAMES = lldCOFF lldCommon lldELF lldMachO lldMinGW lldWasm
|
||||
LLD_LIBS = $(START_GROUP) $(addprefix -l,$(LLD_LIB_NAMES)) $(END_GROUP)
|
||||
|
||||
# Other libraries that are needed to link TinyGo.
|
||||
EXTRA_LIB_NAMES = LLVMInterpreter
|
||||
EXTRA_LIB_NAMES = LLVMInterpreter LLVMMCA LLVMX86TargetMCA
|
||||
|
||||
# All libraries to be built and linked with the tinygo binary (lib/lib*.a).
|
||||
LIB_NAMES = clang $(CLANG_LIB_NAMES) $(LLD_LIB_NAMES) $(EXTRA_LIB_NAMES)
|
||||
@@ -110,9 +133,9 @@ NINJA_BUILD_TARGETS = clang llvm-config llvm-ar llvm-nm $(addprefix lib/lib,$(ad
|
||||
|
||||
# For static linking.
|
||||
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
|
||||
CGO_CPPFLAGS+=$(shell $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
|
||||
CGO_CPPFLAGS+=$(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
|
||||
CGO_CXXFLAGS=-std=c++14
|
||||
CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
|
||||
CGO_LDFLAGS+=-L$(abspath $(LLVM_BUILDDIR)/lib) -lclang $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_CONFIG_PREFIX) $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
|
||||
endif
|
||||
|
||||
clean:
|
||||
@@ -175,7 +198,7 @@ gen-device-rp: build/gen-device-svd
|
||||
|
||||
# Get LLVM sources.
|
||||
$(LLVM_PROJECTDIR)/llvm:
|
||||
git clone -b xtensa_release_13.0.0 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
|
||||
git clone -b xtensa_release_14.0.0-patched --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
|
||||
llvm-source: $(LLVM_PROJECTDIR)/llvm
|
||||
|
||||
# Configure LLVM.
|
||||
@@ -208,21 +231,18 @@ lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
|
||||
# Build the Go compiler.
|
||||
tinygo:
|
||||
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " make llvm-source"; echo " make $(LLVM_BUILDDIR)"; exit 1; fi
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
|
||||
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
|
||||
test: wasi-libc
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags byollvm ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||
|
||||
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
|
||||
TEST_PACKAGES_SLOW = \
|
||||
compress/bzip2 \
|
||||
compress/flate \
|
||||
crypto/dsa \
|
||||
index/suffixarray \
|
||||
|
||||
# Standard library packages that pass tests quickly on darwin, linux, wasi, and windows
|
||||
TEST_PACKAGES_FAST = \
|
||||
compress/lzw \
|
||||
compress/zlib \
|
||||
container/heap \
|
||||
container/list \
|
||||
@@ -269,10 +289,14 @@ TEST_PACKAGES_FAST = \
|
||||
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows
|
||||
# io/fs requires os.ReadDir, which is not yet supported on windows or wasi
|
||||
# testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi
|
||||
# compress/flate fails windows go 1.18, https://github.com/tinygo-org/tinygo/issues/2762
|
||||
# compress/lzw fails windows go 1.18 wasi, https://github.com/tinygo-org/tinygo/issues/2762
|
||||
|
||||
# Additional standard library packages that pass tests on individual platforms
|
||||
TEST_PACKAGES_LINUX := \
|
||||
archive/zip \
|
||||
compress/flate \
|
||||
compress/lzw \
|
||||
debug/dwarf \
|
||||
debug/plan9obj \
|
||||
io/fs \
|
||||
@@ -280,6 +304,9 @@ TEST_PACKAGES_LINUX := \
|
||||
|
||||
TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
|
||||
|
||||
TEST_PACKAGES_WINDOWS := \
|
||||
compress/lzw
|
||||
|
||||
# Report platforms on which each standard library package is known to pass tests
|
||||
jointmp := $(shell echo /tmp/join.$$$$)
|
||||
report-stdlib-tests-pass:
|
||||
@@ -298,7 +325,7 @@ ifeq ($(shell uname),Linux)
|
||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_LINUX)
|
||||
endif
|
||||
ifeq ($(OS),Windows_NT)
|
||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST)
|
||||
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_WINDOWS)
|
||||
endif
|
||||
|
||||
# Test known-working standard library packages.
|
||||
@@ -388,6 +415,8 @@ ifneq ($(WASM), 0)
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_express examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_bluefruit examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
endif
|
||||
# test all targets/boards
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040-s132v6 examples/blinky1
|
||||
@@ -619,7 +648,6 @@ build/release: tinygo gen-device wasi-libc $(if $(filter 1,$(USE_SYSTEM_BINARYEN
|
||||
@mkdir -p build/release/tinygo/bin
|
||||
@mkdir -p build/release/tinygo/lib/clang/include
|
||||
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
|
||||
@mkdir -p build/release/tinygo/lib/compiler-rt/lib
|
||||
@mkdir -p build/release/tinygo/lib/macos-minimal-sdk
|
||||
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-crt/lib-common
|
||||
@mkdir -p build/release/tinygo/lib/mingw-w64/mingw-w64-headers/defaults
|
||||
@@ -641,9 +669,6 @@ endif
|
||||
@cp -p $(abspath $(CLANG_SRC))/lib/Headers/*.h build/release/tinygo/lib/clang/include
|
||||
@cp -rp lib/CMSIS/CMSIS/Include build/release/tinygo/lib/CMSIS/CMSIS
|
||||
@cp -rp lib/CMSIS/README.md build/release/tinygo/lib/CMSIS
|
||||
@cp -rp lib/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt/lib
|
||||
@cp -rp lib/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt
|
||||
@cp -rp lib/compiler-rt/README.txt build/release/tinygo/lib/compiler-rt
|
||||
@cp -rp lib/macos-minimal-sdk/* build/release/tinygo/lib/macos-minimal-sdk
|
||||
@cp -rp lib/musl/arch/aarch64 build/release/tinygo/lib/musl/arch
|
||||
@cp -rp lib/musl/arch/arm build/release/tinygo/lib/musl/arch
|
||||
@@ -680,6 +705,8 @@ endif
|
||||
@cp -rp lib/picolibc/newlib/libm/common build/release/tinygo/lib/picolibc/newlib/libm
|
||||
@cp -rp lib/picolibc-stdio.c build/release/tinygo/lib
|
||||
@cp -rp lib/wasi-libc/sysroot build/release/tinygo/lib/wasi-libc/sysroot
|
||||
@cp -rp llvm-project/compiler-rt/lib/builtins build/release/tinygo/lib/compiler-rt-builtins
|
||||
@cp -rp llvm-project/compiler-rt/LICENSE.TXT build/release/tinygo/lib/compiler-rt-builtins
|
||||
@cp -rp src build/release/tinygo/src
|
||||
@cp -rp targets build/release/tinygo/targets
|
||||
./build/tinygo build-library -target=cortex-m0 -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0/compiler-rt compiler-rt
|
||||
@@ -689,12 +716,18 @@ endif
|
||||
./build/tinygo build-library -target=cortex-m0plus -o build/release/tinygo/pkg/thumbv6m-unknown-unknown-eabi-cortex-m0plus/picolibc picolibc
|
||||
./build/tinygo build-library -target=cortex-m4 -o build/release/tinygo/pkg/thumbv7em-unknown-unknown-eabi-cortex-m4/picolibc picolibc
|
||||
|
||||
release: build/release
|
||||
release:
|
||||
tar -czf build/release.tar.gz -C build/release tinygo
|
||||
|
||||
deb: build/release
|
||||
DEB_ARCH ?= native
|
||||
deb:
|
||||
@mkdir -p build/release-deb/usr/local/bin
|
||||
@mkdir -p build/release-deb/usr/local/lib
|
||||
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
|
||||
fpm -f -s dir -t deb -n tinygo -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)
|
||||
release: build/release
|
||||
deb: build/release
|
||||
endif
|
||||
|
||||
@@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
|
||||
|
||||
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
||||
|
||||
The following 82 microcontroller boards are currently supported:
|
||||
The following 85 microcontroller boards are currently supported:
|
||||
|
||||
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||
@@ -85,6 +85,7 @@ The following 82 microcontroller boards are currently supported:
|
||||
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
|
||||
* [ESP32 - Core board](https://www.espressif.com/en/products/socs/esp32)
|
||||
* [ESP32 - mini32](https://www.espressif.com/en/products/socs/esp32)
|
||||
* [ESP32-C3-12f](https://www.espressif.com/en/products/socs/esp32-c3)
|
||||
* [ESP8266 - d1mini](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [ESP8266 - NodeMCU](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
|
||||
@@ -112,10 +113,12 @@ The following 82 microcontroller boards are currently supported:
|
||||
* [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)
|
||||
* [Raytac MDBT50Q-RX Dongle (with TinyUF2 bootloader)](https://www.adafruit.com/product/5199)
|
||||
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
|
||||
* [Seeed XIAO BLE](https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html)
|
||||
* [Seeed LoRa-E5 Development Kit](https://www.seeedstudio.com/LoRa-E5-Dev-Kit-p-4868.html)
|
||||
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
|
||||
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
|
||||
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1)
|
||||
* [Sparkfun Thing Plus RP2040](https://www.sparkfun.com/products/17745)
|
||||
* [ST Micro "Nucleo" F103RB](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html)
|
||||
* [ST Micro "Nucleo" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
|
||||
* [ST Micro "Nucleo" L031K6](https://www.st.com/ja/evaluation-tools/nucleo-l031k6.html)
|
||||
|
||||
+8
-1
@@ -37,8 +37,14 @@ import (
|
||||
// BuildResult is the output of a build. This includes the binary itself and
|
||||
// some other metadata that is obtained while building the binary.
|
||||
type BuildResult struct {
|
||||
// The executable directly from the linker, usually including debug
|
||||
// information. Used for GDB for example.
|
||||
Executable string
|
||||
|
||||
// A path to the output binary. It will be removed after Build returns, so
|
||||
// if it should be kept it must be copied or moved away.
|
||||
// It is often the same as Executable, but differs if the output format is
|
||||
// .hex for example (instead of the usual ELF).
|
||||
Binary string
|
||||
|
||||
// The directory of the main package. This is useful for testing as the test
|
||||
@@ -835,7 +841,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "esp32", "esp32c3", "esp8266":
|
||||
case "esp32", "esp32-img", "esp32c3", "esp8266":
|
||||
// Special format for the ESP family of chips (parsed by the ROM
|
||||
// bootloader).
|
||||
tmppath = filepath.Join(dir, "main"+outext)
|
||||
@@ -867,6 +873,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
}
|
||||
|
||||
return action(BuildResult{
|
||||
Executable: executable,
|
||||
Binary: tmppath,
|
||||
MainDir: lprogram.MainPkg().Dir,
|
||||
ModuleRoot: moduleroot,
|
||||
|
||||
+14
-1
@@ -1,7 +1,11 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
)
|
||||
|
||||
// These are the GENERIC_SOURCES according to CMakeList.txt.
|
||||
@@ -72,6 +76,7 @@ var genericBuiltins = []string{
|
||||
"floatunsisf.c",
|
||||
"floatuntidf.c",
|
||||
"floatuntisf.c",
|
||||
"fp_mode.c",
|
||||
//"int_util.c",
|
||||
"lshrdi3.c",
|
||||
"lshrti3.c",
|
||||
@@ -161,7 +166,15 @@ var CompilerRT = Library{
|
||||
cflags: func(target, headerPath string) []string {
|
||||
return []string{"-Werror", "-Wall", "-std=c11", "-nostdlibinc"}
|
||||
},
|
||||
sourceDir: "lib/compiler-rt/lib/builtins",
|
||||
sourceDir: func() string {
|
||||
llvmDir := filepath.Join(goenv.Get("TINYGOROOT"), "llvm-project/compiler-rt/lib/builtins")
|
||||
if _, err := os.Stat(llvmDir); err == nil {
|
||||
// Release build.
|
||||
return llvmDir
|
||||
}
|
||||
// Development build.
|
||||
return filepath.Join(goenv.Get("TINYGOROOT"), "lib/compiler-rt-builtins")
|
||||
},
|
||||
librarySources: func(target string) []string {
|
||||
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
|
||||
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
||||
|
||||
+3
-4
@@ -38,6 +38,7 @@
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.h"
|
||||
#include "llvm/MC/MCTargetOptions.h"
|
||||
#include "llvm/MC/TargetRegistry.h"
|
||||
#include "llvm/Option/Arg.h"
|
||||
#include "llvm/Option/ArgList.h"
|
||||
#include "llvm/Option/OptTable.h"
|
||||
@@ -51,7 +52,6 @@
|
||||
#include "llvm/Support/Process.h"
|
||||
#include "llvm/Support/Signals.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
#include "llvm/Support/TargetSelect.h"
|
||||
#include "llvm/Support/Timer.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
@@ -120,7 +120,6 @@ bool AssemblerInvocation::CreateFromArgs(AssemblerInvocation &Opts,
|
||||
llvm::StringSwitch<llvm::DebugCompressionType>(A->getValue())
|
||||
.Case("none", llvm::DebugCompressionType::None)
|
||||
.Case("zlib", llvm::DebugCompressionType::Z)
|
||||
.Case("zlib-gnu", llvm::DebugCompressionType::GNU)
|
||||
.Default(llvm::DebugCompressionType::None);
|
||||
}
|
||||
|
||||
@@ -382,7 +381,7 @@ static bool ExecuteAssemblerImpl(AssemblerInvocation &Opts,
|
||||
T, Ctx, std::move(MAB), std::move(OW), std::move(CE), *STI,
|
||||
Opts.RelaxAll, Opts.IncrementalLinkerCompatible,
|
||||
/*DWARFMustBeAtTheEnd*/ true));
|
||||
Str.get()->InitSections(Opts.NoExecStack);
|
||||
Str.get()->initSections(Opts.NoExecStack, *STI);
|
||||
}
|
||||
|
||||
// When -fembed-bitcode is passed to clang_as, a 1-byte marker
|
||||
@@ -442,7 +441,7 @@ bool ExecuteAssembler(AssemblerInvocation &Opts,
|
||||
return Failed;
|
||||
}
|
||||
|
||||
static void LLVMErrorHandler(void *UserData, const std::string &Message,
|
||||
static void LLVMErrorHandler(void *UserData, const char *Message,
|
||||
bool GenCrashDiag) {
|
||||
DiagnosticsEngine &Diags = *static_cast<DiagnosticsEngine*>(UserData);
|
||||
|
||||
|
||||
+2
-2
@@ -33,8 +33,8 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
|
||||
}
|
||||
if major != 1 || minor < 15 || minor > 17 {
|
||||
return nil, fmt.Errorf("requires go version 1.15 through 1.17, got go%d.%d", major, minor)
|
||||
if major != 1 || minor < 15 || minor > 18 {
|
||||
return nil, fmt.Errorf("requires go version 1.15 through 1.18, got go%d.%d", major, minor)
|
||||
}
|
||||
|
||||
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// Create a job that builds a Darwin libSystem.dylib stub library. This library
|
||||
@@ -38,8 +39,12 @@ func makeDarwinLibSystemJob(config *compileopts.Config, tmpdir string) *compileJ
|
||||
|
||||
// Link object file to dynamic library.
|
||||
platformVersion := strings.TrimPrefix(strings.Split(config.Triple(), "-")[2], "macosx")
|
||||
flavor := "darwin"
|
||||
if strings.Split(llvm.Version, ".")[0] < "13" {
|
||||
flavor = "darwinnew" // needed on LLVM 12 and below
|
||||
}
|
||||
flags = []string{
|
||||
"-flavor", "darwinnew",
|
||||
"-flavor", flavor,
|
||||
"-demangle",
|
||||
"-dynamic",
|
||||
"-dylib",
|
||||
|
||||
+30
-3
@@ -15,6 +15,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type espImageSegment struct {
|
||||
@@ -78,15 +79,31 @@ func makeESPFirmareImage(infile, outfile, format string) error {
|
||||
// An added benefit is that we don't need to check for errors all the time.
|
||||
outf := &bytes.Buffer{}
|
||||
|
||||
// Separate esp32 and esp32-img. The -img suffix indicates we should make an
|
||||
// image, not just a binary to be flashed at 0x1000 for example.
|
||||
chip := format
|
||||
makeImage := false
|
||||
if strings.HasSuffix(format, "-img") {
|
||||
makeImage = true
|
||||
chip = format[:len(format)-len("-img")]
|
||||
}
|
||||
|
||||
if makeImage {
|
||||
// The bootloader starts at 0x1000, or 4096.
|
||||
// TinyGo doesn't use a separate bootloader and runs the entire
|
||||
// application in the bootloader location.
|
||||
outf.Write(make([]byte, 4096))
|
||||
}
|
||||
|
||||
// Chip IDs. Source:
|
||||
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L22
|
||||
chip_id := map[string]uint16{
|
||||
"esp32": 0x0000,
|
||||
"esp32c3": 0x0005,
|
||||
}[format]
|
||||
}[chip]
|
||||
|
||||
// Image header.
|
||||
switch format {
|
||||
switch chip {
|
||||
case "esp32", "esp32c3":
|
||||
// Header format:
|
||||
// https://github.com/espressif/esp-idf/blob/v4.3/components/bootloader_support/include/esp_app_format.h#L71
|
||||
@@ -155,12 +172,22 @@ func makeESPFirmareImage(infile, outfile, format string) error {
|
||||
outf.Write(make([]byte, 15-outf.Len()%16))
|
||||
outf.WriteByte(checksum)
|
||||
|
||||
if format != "esp8266" {
|
||||
if chip != "esp8266" {
|
||||
// SHA256 hash (to protect against image corruption, not for security).
|
||||
hash := sha256.Sum256(outf.Bytes())
|
||||
outf.Write(hash[:])
|
||||
}
|
||||
|
||||
// QEMU (or more precisely, qemu-system-xtensa from Espressif) expects the
|
||||
// image to be a certain size.
|
||||
if makeImage {
|
||||
// Use a default image size of 4MB.
|
||||
grow := 4096*1024 - outf.Len()
|
||||
if grow > 0 {
|
||||
outf.Write(make([]byte, grow))
|
||||
}
|
||||
}
|
||||
|
||||
// Write the image to the output file.
|
||||
return ioutil.WriteFile(outfile, outf.Bytes(), 0666)
|
||||
}
|
||||
|
||||
+13
-5
@@ -24,8 +24,8 @@ type Library struct {
|
||||
// cflags returns the C flags specific to this library
|
||||
cflags func(target, headerPath string) []string
|
||||
|
||||
// The source directory, relative to TINYGOROOT.
|
||||
sourceDir string
|
||||
// The source directory.
|
||||
sourceDir func() string
|
||||
|
||||
// The source files, relative to sourceDir.
|
||||
librarySources func(target string) []string
|
||||
@@ -153,7 +153,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
||||
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables")
|
||||
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
|
||||
}
|
||||
if strings.HasPrefix(target, "riscv32-") {
|
||||
args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128")
|
||||
@@ -161,6 +161,12 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
if strings.HasPrefix(target, "riscv64-") {
|
||||
args = append(args, "-march=rv64gc", "-mabi=lp64")
|
||||
}
|
||||
if strings.HasPrefix(target, "xtensa") {
|
||||
// Hack to work around an issue in the Xtensa port:
|
||||
// https://github.com/espressif/llvm-project/issues/52
|
||||
// Hopefully this will be fixed soon (LLVM 14).
|
||||
args = append(args, "-D__ELF__")
|
||||
}
|
||||
|
||||
var once sync.Once
|
||||
|
||||
@@ -195,6 +201,8 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
},
|
||||
}
|
||||
|
||||
sourceDir := l.sourceDir()
|
||||
|
||||
// Create jobs to compile all sources. These jobs are depended upon by the
|
||||
// archive job above, so must be run first.
|
||||
for _, path := range l.librarySources(target) {
|
||||
@@ -203,7 +211,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
for strings.HasPrefix(cleanpath, "../") {
|
||||
cleanpath = cleanpath[3:]
|
||||
}
|
||||
srcpath := filepath.Join(goenv.Get("TINYGOROOT"), l.sourceDir, path)
|
||||
srcpath := filepath.Join(sourceDir, path)
|
||||
objpath := filepath.Join(dir, cleanpath+".o")
|
||||
os.MkdirAll(filepath.Dir(objpath), 0o777)
|
||||
objs = append(objs, objpath)
|
||||
@@ -227,7 +235,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
||||
// (It could be done in parallel with creating the ar file, but it probably
|
||||
// won't make much of a difference in speed).
|
||||
if l.crt1Source != "" {
|
||||
srcpath := filepath.Join(goenv.Get("TINYGOROOT"), l.sourceDir, l.crt1Source)
|
||||
srcpath := filepath.Join(sourceDir, l.crt1Source)
|
||||
job.dependencies = append(job.dependencies, &compileJob{
|
||||
description: "compile " + srcpath,
|
||||
run: func(*compileJob) error {
|
||||
|
||||
+4
-4
@@ -8,22 +8,22 @@ extern "C" {
|
||||
|
||||
bool tinygo_link_elf(int argc, char **argv) {
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::elf::link(args, false, llvm::outs(), llvm::errs());
|
||||
return lld::elf::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
}
|
||||
|
||||
bool tinygo_link_macho(int argc, char **argv) {
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::macho::link(args, false, llvm::outs(), llvm::errs());
|
||||
return lld::macho::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
}
|
||||
|
||||
bool tinygo_link_mingw(int argc, char **argv) {
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::mingw::link(args, false, llvm::outs(), llvm::errs());
|
||||
return lld::mingw::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
}
|
||||
|
||||
bool tinygo_link_wasm(int argc, char **argv) {
|
||||
std::vector<const char*> args(argv, argv + argc);
|
||||
return lld::wasm::link(args, false, llvm::outs(), llvm::errs());
|
||||
return lld::wasm::link(args, llvm::outs(), llvm::errs(), false, false);
|
||||
}
|
||||
|
||||
} // external "C"
|
||||
|
||||
@@ -26,6 +26,7 @@ var MinGW = Library{
|
||||
_, err = io.Copy(outf, inf)
|
||||
return err
|
||||
},
|
||||
sourceDir: func() string { return "" }, // unused
|
||||
cflags: func(target, headerPath string) []string {
|
||||
// No flags necessary because there are no files to compile.
|
||||
return nil
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ var Musl = Library{
|
||||
"-fno-stack-protector",
|
||||
}
|
||||
},
|
||||
sourceDir: "lib/musl/src",
|
||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/musl/src") },
|
||||
librarySources: func(target string) []string {
|
||||
arch := compileopts.MuslArchitecture(target)
|
||||
globs := []string{
|
||||
|
||||
+1
-1
@@ -33,7 +33,7 @@ var Picolibc = Library{
|
||||
"-I" + headerPath,
|
||||
}
|
||||
},
|
||||
sourceDir: "lib/picolibc/newlib/libc",
|
||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib/libc") },
|
||||
librarySources: func(target string) []string {
|
||||
return picolibcSources
|
||||
},
|
||||
|
||||
@@ -54,7 +54,7 @@ func RunTool(tool string, args ...string) error {
|
||||
ok = C.tinygo_clang_driver(C.int(len(args)), (**C.char)(buf))
|
||||
case "ld.lld":
|
||||
switch linker {
|
||||
case "darwinnew":
|
||||
case "darwin", "darwinnew": // darwinnew is only needed for LLVM 12 and below
|
||||
ok = C.tinygo_link_macho(C.int(len(args)), (**C.char)(buf))
|
||||
case "elf":
|
||||
ok = C.tinygo_link_elf(C.int(len(args)), (**C.char)(buf))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//go:build !byollvm && !llvm11 && !llvm12
|
||||
// +build !byollvm,!llvm11,!llvm12
|
||||
//go:build !byollvm && !llvm11 && !llvm12 && !llvm14
|
||||
// +build !byollvm,!llvm11,!llvm12,!llvm14
|
||||
|
||||
package cgo
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
//go:build !byollvm && llvm14
|
||||
// +build !byollvm,llvm14
|
||||
|
||||
package cgo
|
||||
|
||||
/*
|
||||
#cgo linux CFLAGS: -I/usr/lib/llvm-14/include
|
||||
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@14/include
|
||||
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@14/include
|
||||
#cgo freebsd CFLAGS: -I/usr/local/llvm14/include
|
||||
#cgo linux LDFLAGS: -L/usr/lib/llvm-14/lib -lclang
|
||||
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@14/lib -lclang -lffi
|
||||
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@14/lib -lclang -lffi
|
||||
#cgo freebsd LDFLAGS: -L/usr/local/llvm14/lib -lclang
|
||||
*/
|
||||
import "C"
|
||||
+45
-6
@@ -10,6 +10,7 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/google/shlex"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
)
|
||||
|
||||
@@ -287,6 +288,7 @@ func (c *Config) CFlags() []string {
|
||||
path, _ := c.LibcPath("picolibc")
|
||||
cflags = append(cflags,
|
||||
"--sysroot="+path,
|
||||
"-isystem", filepath.Join(path, "include"), // necessary for Xtensa
|
||||
"-isystem", filepath.Join(picolibcDir, "include"),
|
||||
"-isystem", filepath.Join(picolibcDir, "tinystdio"),
|
||||
)
|
||||
@@ -393,6 +395,13 @@ func (c *Config) BinaryFormat(ext string) string {
|
||||
return c.Target.BinaryFormat
|
||||
}
|
||||
return "bin"
|
||||
case ".img":
|
||||
// Image file. Only defined for the ESP32 at the moment, where it is a
|
||||
// full (runnable) image that can be used in the Espressif QEMU fork.
|
||||
if c.Target.BinaryFormat != "" {
|
||||
return c.Target.BinaryFormat + "-img"
|
||||
}
|
||||
return "bin"
|
||||
case ".hex":
|
||||
// Similar to bin, but includes the start address and is thus usually a
|
||||
// better format.
|
||||
@@ -493,13 +502,43 @@ func (c *Config) WasmAbi() string {
|
||||
return c.Target.WasmAbi
|
||||
}
|
||||
|
||||
// Emulator returns the emulator target config
|
||||
func (c *Config) Emulator() []string {
|
||||
var emulator []string
|
||||
for _, s := range c.Target.Emulator {
|
||||
emulator = append(emulator, strings.ReplaceAll(s, "{root}", goenv.Get("TINYGOROOT")))
|
||||
// EmulatorName is a shorthand to get the command for this emulator, something
|
||||
// like qemu-system-arm or simavr.
|
||||
func (c *Config) EmulatorName() string {
|
||||
parts := strings.SplitN(c.Target.Emulator, " ", 2)
|
||||
if len(parts) > 1 {
|
||||
return parts[0]
|
||||
}
|
||||
return emulator
|
||||
return ""
|
||||
}
|
||||
|
||||
// EmulatorFormat returns the binary format for the emulator and the associated
|
||||
// file extension. An empty string means to pass directly whatever the linker
|
||||
// produces directly without conversion (usually ELF format).
|
||||
func (c *Config) EmulatorFormat() (format, fileExt string) {
|
||||
switch {
|
||||
case strings.Contains(c.Target.Emulator, "{img}"):
|
||||
return "img", ".img"
|
||||
default:
|
||||
return "", ""
|
||||
}
|
||||
}
|
||||
|
||||
// Emulator returns a ready-to-run command to run the given binary in an
|
||||
// emulator. Give it the format (returned by EmulatorFormat()) and the path to
|
||||
// the compiled binary.
|
||||
func (c *Config) Emulator(format, binary string) ([]string, error) {
|
||||
parts, err := shlex.Split(c.Target.Emulator)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not parse emulator command: %w", err)
|
||||
}
|
||||
var emulator []string
|
||||
for _, s := range parts {
|
||||
s = strings.ReplaceAll(s, "{root}", goenv.Get("TINYGOROOT"))
|
||||
s = strings.ReplaceAll(s, "{"+format+"}", binary)
|
||||
emulator = append(emulator, s)
|
||||
}
|
||||
return emulator, nil
|
||||
}
|
||||
|
||||
type TestConfig struct {
|
||||
|
||||
+16
-22
@@ -44,8 +44,8 @@ type TargetSpec struct {
|
||||
LDFlags []string `json:"ldflags"`
|
||||
LinkerScript string `json:"linkerscript"`
|
||||
ExtraFiles []string `json:"extra-files"`
|
||||
RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
|
||||
Emulator []string `json:"emulator" override:"copy"` // inherited Emulator must not be append
|
||||
RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
|
||||
Emulator string `json:"emulator"`
|
||||
FlashCommand string `json:"flash-command"`
|
||||
GDB []string `json:"gdb"`
|
||||
PortReset string `json:"flash-1200-bps-reset"`
|
||||
@@ -59,6 +59,7 @@ type TargetSpec struct {
|
||||
OpenOCDTarget string `json:"openocd-target"`
|
||||
OpenOCDTransport string `json:"openocd-transport"`
|
||||
OpenOCDCommands []string `json:"openocd-commands"`
|
||||
OpenOCDVerify *bool `json:"openocd-verify"` // enable verify when flashing with openocd
|
||||
JLinkDevice string `json:"jlink-device"`
|
||||
CodeModel string `json:"code-model"`
|
||||
RelocationModel string `json:"relocation-model"`
|
||||
@@ -89,19 +90,8 @@ func (spec *TargetSpec) overrideProperties(child *TargetSpec) {
|
||||
if !src.IsNil() {
|
||||
dst.Set(src)
|
||||
}
|
||||
case reflect.Slice: // for slices...
|
||||
if src.Len() > 0 { // ... if not empty ...
|
||||
switch tag := field.Tag.Get("override"); tag {
|
||||
case "copy":
|
||||
// copy the field of child to spec
|
||||
dst.Set(src)
|
||||
case "append", "":
|
||||
// or append the field of child to spec
|
||||
dst.Set(reflect.AppendSlice(dst, src))
|
||||
default:
|
||||
panic("override mode must be 'copy' or 'append' (default). I don't know how to '" + tag + "'.")
|
||||
}
|
||||
}
|
||||
case reflect.Slice: // for slices, append the field
|
||||
dst.Set(reflect.AppendSlice(dst, src))
|
||||
default:
|
||||
panic("unknown field type : " + kind.String())
|
||||
}
|
||||
@@ -258,7 +248,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
spec.Features = "+cx8,+fxsr,+mmx,+sse,+sse2,+x87"
|
||||
case "arm":
|
||||
spec.CPU = "generic"
|
||||
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables")
|
||||
spec.CFlags = append(spec.CFlags, "-fno-unwind-tables", "-fno-asynchronous-unwind-tables")
|
||||
switch strings.Split(triple, "-")[0] {
|
||||
case "armv5":
|
||||
spec.Features = "+armv5t,+strict-align,-aes,-bf16,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-mve.fp,-neon,-sha2,-thumb-mode,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
@@ -276,8 +266,12 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
spec.Libc = "darwin-libSystem"
|
||||
arch := strings.Split(triple, "-")[0]
|
||||
platformVersion := strings.TrimPrefix(strings.Split(triple, "-")[2], "macosx")
|
||||
flavor := "darwin"
|
||||
if strings.Split(llvm.Version, ".")[0] < "13" {
|
||||
flavor = "darwinnew" // needed on LLVM 12 and below
|
||||
}
|
||||
spec.LDFlags = append(spec.LDFlags,
|
||||
"-flavor", "darwinnew",
|
||||
"-flavor", flavor,
|
||||
"-dead_strip",
|
||||
"-arch", arch,
|
||||
"-platform_version", "macos", platformVersion, platformVersion,
|
||||
@@ -330,20 +324,20 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
case "386":
|
||||
// amd64 can _usually_ run 32-bit programs, so skip the emulator in that case.
|
||||
if runtime.GOARCH != "amd64" {
|
||||
spec.Emulator = []string{"qemu-i386"}
|
||||
spec.Emulator = "qemu-i386 {}"
|
||||
}
|
||||
case "amd64":
|
||||
spec.Emulator = []string{"qemu-x86_64"}
|
||||
spec.Emulator = "qemu-x86_64 {}"
|
||||
case "arm":
|
||||
spec.Emulator = []string{"qemu-arm"}
|
||||
spec.Emulator = "qemu-arm {}"
|
||||
case "arm64":
|
||||
spec.Emulator = []string{"qemu-aarch64"}
|
||||
spec.Emulator = "qemu-aarch64 {}"
|
||||
}
|
||||
}
|
||||
}
|
||||
if goos != runtime.GOOS {
|
||||
if goos == "windows" {
|
||||
spec.Emulator = []string{"wine"}
|
||||
spec.Emulator = "wine {}"
|
||||
}
|
||||
}
|
||||
return &spec, nil
|
||||
|
||||
@@ -29,7 +29,6 @@ func TestOverrideProperties(t *testing.T) {
|
||||
CPU: "baseCpu",
|
||||
CFlags: []string{"-base-foo", "-base-bar"},
|
||||
BuildTags: []string{"bt1", "bt2"},
|
||||
Emulator: []string{"be1", "be2"},
|
||||
DefaultStackSize: 42,
|
||||
AutoStackSize: &baseAutoStackSize,
|
||||
}
|
||||
@@ -38,7 +37,6 @@ func TestOverrideProperties(t *testing.T) {
|
||||
GOOS: "",
|
||||
CPU: "chlidCpu",
|
||||
CFlags: []string{"-child-foo", "-child-bar"},
|
||||
Emulator: []string{"ce1", "ce2"},
|
||||
AutoStackSize: &childAutoStackSize,
|
||||
DefaultStackSize: 64,
|
||||
}
|
||||
@@ -57,9 +55,6 @@ func TestOverrideProperties(t *testing.T) {
|
||||
if !reflect.DeepEqual(base.BuildTags, []string{"bt1", "bt2"}) {
|
||||
t.Errorf("Overriding failed : got %v", base.BuildTags)
|
||||
}
|
||||
if !reflect.DeepEqual(base.Emulator, []string{"ce1", "ce2"}) {
|
||||
t.Errorf("Overriding failed : got %v", base.Emulator)
|
||||
}
|
||||
if *base.AutoStackSize != false {
|
||||
t.Errorf("Overriding failed : got %v", base.AutoStackSize)
|
||||
}
|
||||
|
||||
+18
-6
@@ -957,10 +957,10 @@ func (b *builder) createFunction() {
|
||||
} else {
|
||||
fieldOffsets := b.expandFormalParamOffsets(llvmType)
|
||||
for i, field := range fields {
|
||||
expr := b.dibuilder.CreateExpression([]int64{
|
||||
0x1000, // DW_OP_LLVM_fragment
|
||||
int64(fieldOffsets[i]) * 8, // offset in bits
|
||||
int64(b.targetData.TypeAllocSize(field.Type())) * 8, // size in bits
|
||||
expr := b.dibuilder.CreateExpression([]uint64{
|
||||
0x1000, // DW_OP_LLVM_fragment
|
||||
fieldOffsets[i] * 8, // offset in bits
|
||||
b.targetData.TypeAllocSize(field.Type()) * 8, // size in bits
|
||||
})
|
||||
b.dibuilder.InsertValueAtEnd(field, dbgParam, expr, loc, entryBlock)
|
||||
}
|
||||
@@ -1440,7 +1440,7 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
return b.emitSV64Call(instr.Args)
|
||||
case strings.HasPrefix(name, "(device/riscv.CSR)."):
|
||||
return b.emitCSROperation(instr)
|
||||
case strings.HasPrefix(name, "syscall.Syscall"):
|
||||
case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall"):
|
||||
return b.createSyscall(instr)
|
||||
case strings.HasPrefix(name, "syscall.rawSyscallNoError"):
|
||||
return b.createRawSyscallNoError(instr)
|
||||
@@ -1469,6 +1469,14 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
case *ssa.Function:
|
||||
// Regular function call. No context is necessary.
|
||||
context = llvm.Undef(b.i8ptrType)
|
||||
if info.variadic && len(fn.Params) == 0 {
|
||||
// This matches Clang, see: https://godbolt.org/z/Gqv49xKMq
|
||||
// Eventually we might be able to eliminate this special case
|
||||
// entirely. For details, see:
|
||||
// https://discourse.llvm.org/t/rfc-enabling-wstrict-prototypes-by-default-in-c/60521
|
||||
fnType := llvm.FunctionType(callee.Type().ElementType().ReturnType(), nil, false)
|
||||
callee = llvm.ConstBitCast(callee, llvm.PointerType(fnType, b.funcPtrAddrSpace))
|
||||
}
|
||||
case *ssa.MakeClosure:
|
||||
// A call on a func value, but the callee is trivial to find. For
|
||||
// example: immediately applied functions.
|
||||
@@ -1554,7 +1562,11 @@ func (c *compilerContext) maxSliceSize(elementType llvm.Type) uint64 {
|
||||
// Determine the maximum allowed size for a slice. The biggest possible
|
||||
// pointer (starting from 0) would be maxPointerValue*sizeof(elementType) so
|
||||
// divide by the element type to get the real maximum size.
|
||||
maxSize := maxPointerValue / c.targetData.TypeAllocSize(elementType)
|
||||
elementSize := c.targetData.TypeAllocSize(elementType)
|
||||
if elementSize == 0 {
|
||||
elementSize = 1
|
||||
}
|
||||
maxSize := maxPointerValue / elementSize
|
||||
|
||||
// len(slice) is an int. Make sure the length remains small enough to fit in
|
||||
// an int.
|
||||
|
||||
@@ -226,9 +226,9 @@ func filterIrrelevantIRLines(lines []string) []string {
|
||||
// Right now test outputs are for LLVM 12 and higher.
|
||||
continue
|
||||
}
|
||||
if llvmVersion < 13 && strings.HasPrefix(line, "target datalayout = ") {
|
||||
if llvmVersion < 14 && strings.HasPrefix(line, "target datalayout = ") {
|
||||
// The datalayout string may vary betewen LLVM versions.
|
||||
// Right now test outputs are for LLVM 13 and higher.
|
||||
// Right now test outputs are for LLVM 14 and higher.
|
||||
continue
|
||||
}
|
||||
out = append(out, line)
|
||||
|
||||
@@ -98,7 +98,10 @@ func (b *builder) createInlineAsmFull(instr *ssa.CallCommon) (llvm.Value, error)
|
||||
case llvm.IntegerTypeKind:
|
||||
constraints = append(constraints, "r")
|
||||
case llvm.PointerTypeKind:
|
||||
constraints = append(constraints, "*m")
|
||||
// Memory references require a type in LLVM 14, probably as a
|
||||
// preparation for opaque pointers.
|
||||
err = b.makeError(instr.Pos(), "support for pointer operands was dropped in TinyGo 0.23")
|
||||
return s
|
||||
default:
|
||||
err = b.makeError(instr.Pos(), "unknown type in inline assembly for value: "+name)
|
||||
return s
|
||||
|
||||
+79
-45
@@ -152,6 +152,27 @@ func (c *compilerContext) makeStructTypeFields(typ *types.Struct) llvm.Value {
|
||||
return structGlobal
|
||||
}
|
||||
|
||||
var basicTypes = [...]string{
|
||||
types.Bool: "bool",
|
||||
types.Int: "int",
|
||||
types.Int8: "int8",
|
||||
types.Int16: "int16",
|
||||
types.Int32: "int32",
|
||||
types.Int64: "int64",
|
||||
types.Uint: "uint",
|
||||
types.Uint8: "uint8",
|
||||
types.Uint16: "uint16",
|
||||
types.Uint32: "uint32",
|
||||
types.Uint64: "uint64",
|
||||
types.Uintptr: "uintptr",
|
||||
types.Float32: "float32",
|
||||
types.Float64: "float64",
|
||||
types.Complex64: "complex64",
|
||||
types.Complex128: "complex128",
|
||||
types.String: "string",
|
||||
types.UnsafePointer: "unsafe.Pointer",
|
||||
}
|
||||
|
||||
// getTypeCodeName returns a name for this type that can be used in the
|
||||
// interface lowering pass to assign type codes as expected by the reflect
|
||||
// package. See getTypeCodeNum.
|
||||
@@ -162,48 +183,7 @@ func getTypeCodeName(t types.Type) string {
|
||||
case *types.Array:
|
||||
return "array:" + strconv.FormatInt(t.Len(), 10) + ":" + getTypeCodeName(t.Elem())
|
||||
case *types.Basic:
|
||||
var kind string
|
||||
switch t.Kind() {
|
||||
case types.Bool:
|
||||
kind = "bool"
|
||||
case types.Int:
|
||||
kind = "int"
|
||||
case types.Int8:
|
||||
kind = "int8"
|
||||
case types.Int16:
|
||||
kind = "int16"
|
||||
case types.Int32:
|
||||
kind = "int32"
|
||||
case types.Int64:
|
||||
kind = "int64"
|
||||
case types.Uint:
|
||||
kind = "uint"
|
||||
case types.Uint8:
|
||||
kind = "uint8"
|
||||
case types.Uint16:
|
||||
kind = "uint16"
|
||||
case types.Uint32:
|
||||
kind = "uint32"
|
||||
case types.Uint64:
|
||||
kind = "uint64"
|
||||
case types.Uintptr:
|
||||
kind = "uintptr"
|
||||
case types.Float32:
|
||||
kind = "float32"
|
||||
case types.Float64:
|
||||
kind = "float64"
|
||||
case types.Complex64:
|
||||
kind = "complex64"
|
||||
case types.Complex128:
|
||||
kind = "complex128"
|
||||
case types.String:
|
||||
kind = "string"
|
||||
case types.UnsafePointer:
|
||||
kind = "unsafeptr"
|
||||
default:
|
||||
panic("unknown basic type: " + t.Name())
|
||||
}
|
||||
return "basic:" + kind
|
||||
return "basic:" + basicTypes[t.Kind()]
|
||||
case *types.Chan:
|
||||
return "chan:" + getTypeCodeName(t.Elem())
|
||||
case *types.Interface:
|
||||
@@ -591,23 +571,77 @@ func signature(sig *types.Signature) string {
|
||||
if i > 0 {
|
||||
s += ", "
|
||||
}
|
||||
s += sig.Params().At(i).Type().String()
|
||||
s += typestring(sig.Params().At(i).Type())
|
||||
}
|
||||
s += ")"
|
||||
}
|
||||
if sig.Results().Len() == 0 {
|
||||
// keep as-is
|
||||
} else if sig.Results().Len() == 1 {
|
||||
s += " " + sig.Results().At(0).Type().String()
|
||||
s += " " + typestring(sig.Results().At(0).Type())
|
||||
} else {
|
||||
s += " ("
|
||||
for i := 0; i < sig.Results().Len(); i++ {
|
||||
if i > 0 {
|
||||
s += ", "
|
||||
}
|
||||
s += sig.Results().At(i).Type().String()
|
||||
s += typestring(sig.Results().At(i).Type())
|
||||
}
|
||||
s += ")"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// typestring returns a stable (human-readable) type string for the given type
|
||||
// that can be used for interface equality checks. It is almost (but not
|
||||
// exactly) the same as calling t.String(). The main difference is some
|
||||
// normalization around `byte` vs `uint8` for example.
|
||||
func typestring(t types.Type) string {
|
||||
// See: https://github.com/golang/go/blob/master/src/go/types/typestring.go
|
||||
switch t := t.(type) {
|
||||
case *types.Array:
|
||||
return "[" + strconv.FormatInt(t.Len(), 10) + "]" + typestring(t.Elem())
|
||||
case *types.Basic:
|
||||
return basicTypes[t.Kind()]
|
||||
case *types.Chan:
|
||||
switch t.Dir() {
|
||||
case types.SendRecv:
|
||||
return "chan (" + typestring(t.Elem()) + ")"
|
||||
case types.SendOnly:
|
||||
return "chan<- (" + typestring(t.Elem()) + ")"
|
||||
case types.RecvOnly:
|
||||
return "<-chan (" + typestring(t.Elem()) + ")"
|
||||
default:
|
||||
panic("unknown channel direction")
|
||||
}
|
||||
case *types.Interface:
|
||||
methods := make([]string, t.NumMethods())
|
||||
for i := range methods {
|
||||
method := t.Method(i)
|
||||
methods[i] = method.Name() + signature(method.Type().(*types.Signature))
|
||||
}
|
||||
return "interface{" + strings.Join(methods, ";") + "}"
|
||||
case *types.Map:
|
||||
return "map[" + typestring(t.Key()) + "]" + typestring(t.Elem())
|
||||
case *types.Named:
|
||||
return t.String()
|
||||
case *types.Pointer:
|
||||
return "*" + typestring(t.Elem())
|
||||
case *types.Signature:
|
||||
return "func" + signature(t)
|
||||
case *types.Slice:
|
||||
return "[]" + typestring(t.Elem())
|
||||
case *types.Struct:
|
||||
fields := make([]string, t.NumFields())
|
||||
for i := range fields {
|
||||
field := t.Field(i)
|
||||
fields[i] = field.Name() + " " + typestring(field.Type())
|
||||
if tag := t.Tag(i); tag != "" {
|
||||
fields[i] += " " + strconv.Quote(tag)
|
||||
}
|
||||
}
|
||||
return "struct{" + strings.Join(fields, ";") + "}"
|
||||
default:
|
||||
panic("unknown type: " + t.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func (c *checker) checkType(t llvm.Type, checked map[llvm.Type]struct{}, special
|
||||
return fmt.Errorf("type %q uses global context", t.String())
|
||||
default:
|
||||
// we used some other context by accident
|
||||
return fmt.Errorf("type %q uses context %v instead of the main context %v", t.Context(), c.ctx)
|
||||
return fmt.Errorf("type %q uses context %v instead of the main context %v", t.String(), t.Context(), c.ctx)
|
||||
}
|
||||
|
||||
// if this is a composite type, check the components of the type
|
||||
|
||||
+13
-1
@@ -10,6 +10,13 @@ import (
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// constants for hashmap algorithms; must match src/runtime/hashmap.go
|
||||
const (
|
||||
hashmapAlgorithmBinary = iota
|
||||
hashmapAlgorithmString
|
||||
hashmapAlgorithmInterface
|
||||
)
|
||||
|
||||
// createMakeMap creates a new map object (runtime.hashmap) by allocating and
|
||||
// initializing an appropriately sized object.
|
||||
func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||
@@ -17,22 +24,27 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||
keyType := mapType.Key().Underlying()
|
||||
llvmValueType := b.getLLVMType(mapType.Elem().Underlying())
|
||||
var llvmKeyType llvm.Type
|
||||
var alg uint64 // must match values in src/runtime/hashmap.go
|
||||
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
|
||||
// String keys.
|
||||
llvmKeyType = b.getLLVMType(keyType)
|
||||
alg = hashmapAlgorithmString
|
||||
} else if hashmapIsBinaryKey(keyType) {
|
||||
// Trivially comparable keys.
|
||||
llvmKeyType = b.getLLVMType(keyType)
|
||||
alg = hashmapAlgorithmBinary
|
||||
} else {
|
||||
// All other keys. Implemented as map[interface{}]valueType for ease of
|
||||
// implementation.
|
||||
llvmKeyType = b.getLLVMRuntimeType("_interface")
|
||||
alg = hashmapAlgorithmInterface
|
||||
}
|
||||
keySize := b.targetData.TypeAllocSize(llvmKeyType)
|
||||
valueSize := b.targetData.TypeAllocSize(llvmValueType)
|
||||
llvmKeySize := llvm.ConstInt(b.ctx.Int8Type(), keySize, false)
|
||||
llvmValueSize := llvm.ConstInt(b.ctx.Int8Type(), valueSize, false)
|
||||
sizeHint := llvm.ConstInt(b.uintptrType, 8, false)
|
||||
algEnum := llvm.ConstInt(b.ctx.Int8Type(), alg, false)
|
||||
if expr.Reserve != nil {
|
||||
sizeHint = b.getValue(expr.Reserve)
|
||||
var err error
|
||||
@@ -41,7 +53,7 @@ func (b *builder) createMakeMap(expr *ssa.MakeMap) (llvm.Value, error) {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
}
|
||||
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint}, "")
|
||||
hashmap := b.createRuntimeCall("hashmapMake", []llvm.Value{llvmKeySize, llvmValueSize, sizeHint, algEnum}, "")
|
||||
return hashmap, nil
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'basic.go'
|
||||
source_filename = "basic.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%main.kv = type { float }
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'channel.go'
|
||||
source_filename = "channel.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'float.go'
|
||||
source_filename = "float.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'func.go'
|
||||
source_filename = "func.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'gc.go'
|
||||
source_filename = "gc.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'go1.17.go'
|
||||
source_filename = "go1.17.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'goroutine.go'
|
||||
source_filename = "goroutine.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||
|
||||
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'interface.go'
|
||||
source_filename = "interface.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID*, i32 }
|
||||
@@ -128,5 +128,5 @@ declare %runtime._string @"interface:{Error:func:{}{basic:string}}.Error$invoke"
|
||||
attributes #0 = { nounwind }
|
||||
attributes #1 = { "tinygo-methods"="reflect/methods.Error() string" }
|
||||
attributes #2 = { "tinygo-methods"="reflect/methods.String() string" }
|
||||
attributes #3 = { "tinygo-invoke"="main.$methods.foo(int) byte" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) byte" }
|
||||
attributes #3 = { "tinygo-invoke"="main.$methods.foo(int) uint8" "tinygo-methods"="reflect/methods.String() string; main.$methods.foo(int) uint8" }
|
||||
attributes #4 = { "tinygo-invoke"="reflect/methods.Error() string" "tinygo-methods"="reflect/methods.Error() string" }
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'intrinsics.go'
|
||||
source_filename = "intrinsics.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'pointer.go'
|
||||
source_filename = "pointer.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'pragma.go'
|
||||
source_filename = "pragma.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
@extern_global = external global [0 x i8], align 1
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'slice.go'
|
||||
source_filename = "slice.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
; ModuleID = 'string.go'
|
||||
source_filename = "string.go"
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime._string = type { i8*, i32 }
|
||||
|
||||
@@ -15,5 +15,5 @@ require (
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
|
||||
golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
tinygo.org/x/go-llvm v0.0.0-20220211075103-ee4aad45c3a1
|
||||
tinygo.org/x/go-llvm v0.0.0-20220420140351-512c94c1e71f
|
||||
)
|
||||
|
||||
@@ -80,5 +80,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
tinygo.org/x/go-llvm v0.0.0-20220211075103-ee4aad45c3a1 h1:6G8AxueDdqobCEqQrmHPLaEH1AZ1p6Y7rGElDNT7N98=
|
||||
tinygo.org/x/go-llvm v0.0.0-20220211075103-ee4aad45c3a1/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||
tinygo.org/x/go-llvm v0.0.0-20220420140351-512c94c1e71f h1:9/J+NpFTpAhYcbh1mC4dr9W/aAPnwrUh8dmq21xWdSM=
|
||||
tinygo.org/x/go-llvm v0.0.0-20220420140351-512c94c1e71f/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
|
||||
|
||||
+3
-3
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const Version = "0.23.0-dev"
|
||||
const Version = "0.23.0"
|
||||
|
||||
var (
|
||||
// This variable is set at build time using -ldflags parameters.
|
||||
@@ -58,9 +58,9 @@ func GorootVersionString(goroot string) (string, error) {
|
||||
return string(data), nil
|
||||
|
||||
} else if data, err := ioutil.ReadFile(filepath.Join(
|
||||
goroot, "src", "runtime", "internal", "sys", "zversion.go")); err == nil {
|
||||
goroot, "src", "internal", "buildcfg", "zbootstrap.go")); err == nil {
|
||||
|
||||
r := regexp.MustCompile("const TheVersion = `(.*)`")
|
||||
r := regexp.MustCompile("const version = `(.*)`")
|
||||
matches := r.FindSubmatch(data)
|
||||
if len(matches) != 2 {
|
||||
return "", errors.New("Invalid go version output:\n" + string(data))
|
||||
|
||||
Vendored
+1
-4
@@ -1,8 +1,6 @@
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64--linux"
|
||||
|
||||
@"main$alloc.1" = internal unnamed_addr constant [6 x i8] c"\05\00{\00\00\04", align 8
|
||||
|
||||
declare void @runtime.printuint8(i8) local_unnamed_addr
|
||||
|
||||
declare void @runtime.printint16(i16) local_unnamed_addr
|
||||
@@ -17,7 +15,6 @@ entry:
|
||||
call void @runtime.printuint8(i8 3)
|
||||
call void @runtime.printuint8(i8 3)
|
||||
call void @runtime.printint16(i16 5)
|
||||
%int16SliceDst.val = load i16, i16* bitcast ([6 x i8]* @"main$alloc.1" to i16*), align 2
|
||||
call void @runtime.printint16(i16 %int16SliceDst.val)
|
||||
call void @runtime.printint16(i16 5)
|
||||
ret void
|
||||
}
|
||||
|
||||
Submodule lib/compiler-rt deleted from 5bc79797e1
@@ -230,6 +230,7 @@ func pathsToOverride(needsSyscallPackage bool) map[string]bool {
|
||||
"device/": false,
|
||||
"examples/": false,
|
||||
"internal/": true,
|
||||
"internal/fuzz/": false,
|
||||
"internal/bytealg/": false,
|
||||
"internal/reflectlite/": false,
|
||||
"internal/task/": false,
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
@@ -199,8 +200,26 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Pass test flags to the test binary.
|
||||
var flags []string
|
||||
if testVerbose {
|
||||
flags = append(flags, "-test.v")
|
||||
}
|
||||
if testShort {
|
||||
flags = append(flags, "-test.short")
|
||||
}
|
||||
if testRunRegexp != "" {
|
||||
flags = append(flags, "-test.run="+testRunRegexp)
|
||||
}
|
||||
if testBenchRegexp != "" {
|
||||
flags = append(flags, "-test.bench="+testBenchRegexp)
|
||||
}
|
||||
if testBenchTime != "" {
|
||||
flags = append(flags, "-test.benchtime="+testBenchTime)
|
||||
}
|
||||
|
||||
passed := false
|
||||
err = builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error {
|
||||
err = buildAndRun(pkgName, config, os.Stdout, flags, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
if testCompileOnly || outpath != "" {
|
||||
// Write test binary to the specified file name.
|
||||
if outpath == "" {
|
||||
@@ -216,27 +235,52 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run the test.
|
||||
config.Options.Semaphore <- struct{}{}
|
||||
defer func() {
|
||||
<-config.Options.Semaphore
|
||||
}()
|
||||
start := time.Now()
|
||||
var err error
|
||||
passed, err = runPackageTest(config, stdout, stderr, result, testVerbose, testShort, testRunRegexp, testBenchRegexp, testBenchTime)
|
||||
if err != nil {
|
||||
return err
|
||||
// Tests are always run in the package directory.
|
||||
cmd.Dir = result.MainDir
|
||||
|
||||
// Wasmtime needs a few extra flags to work.
|
||||
if config.EmulatorName() == "wasmtime" {
|
||||
// Add directories to the module root, but skip the current working
|
||||
// directory which is already added by buildAndRun.
|
||||
dirs := dirsToModuleRoot(result.MainDir, result.ModuleRoot)
|
||||
var args []string
|
||||
for _, d := range dirs[1:] {
|
||||
args = append(args, "--dir="+d)
|
||||
}
|
||||
|
||||
// create a new temp directory just for this run, announce it to os.TempDir() via TMPDIR
|
||||
tmpdir, err := ioutil.TempDir("", "tinygotmp")
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create temporary directory: %w", err)
|
||||
}
|
||||
args = append(args, "--dir="+tmpdir, "--env=TMPDIR="+tmpdir)
|
||||
// TODO: add option to not delete temp dir for debugging?
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
// Insert new argments at the front of the command line argments.
|
||||
args = append(args, cmd.Args[1:]...)
|
||||
cmd.Args = append(cmd.Args[:1:1], args...)
|
||||
}
|
||||
|
||||
// Run the test.
|
||||
start := time.Now()
|
||||
err = cmd.Run()
|
||||
duration := time.Since(start)
|
||||
|
||||
// Print the result.
|
||||
importPath := strings.TrimSuffix(result.ImportPath, ".test")
|
||||
passed = err == nil
|
||||
if passed {
|
||||
fmt.Fprintf(stdout, "ok \t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
} else {
|
||||
fmt.Fprintf(stdout, "FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
}
|
||||
return nil
|
||||
if _, ok := err.(*exec.ExitError); ok {
|
||||
// Binary exited with a non-zero exit code, which means the test
|
||||
// failed.
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
})
|
||||
if err, ok := err.(loader.NoTestFilesError); ok {
|
||||
fmt.Fprintf(stdout, "? \t%s\t[no test files]\n", err.ImportPath)
|
||||
@@ -259,81 +303,6 @@ func dirsToModuleRoot(maindir, modroot string) []string {
|
||||
return dirs
|
||||
}
|
||||
|
||||
// runPackageTest runs a test binary that was previously built. The return
|
||||
// values are whether the test passed and any errors encountered while trying to
|
||||
// run the binary.
|
||||
func runPackageTest(config *compileopts.Config, stdout, stderr io.Writer, result builder.BuildResult, testVerbose, testShort bool, testRunRegexp string, testBenchRegexp string, testBenchTime string) (bool, error) {
|
||||
var cmd *exec.Cmd
|
||||
emulator := config.Emulator()
|
||||
if len(emulator) == 0 {
|
||||
// Run directly.
|
||||
var flags []string
|
||||
if testVerbose {
|
||||
flags = append(flags, "-test.v")
|
||||
}
|
||||
if testShort {
|
||||
flags = append(flags, "-test.short")
|
||||
}
|
||||
if testRunRegexp != "" {
|
||||
flags = append(flags, "-test.run="+testRunRegexp)
|
||||
}
|
||||
if testBenchRegexp != "" {
|
||||
flags = append(flags, "-test.bench="+testBenchRegexp)
|
||||
}
|
||||
if testBenchTime != "" {
|
||||
flags = append(flags, "-test.benchtime="+testBenchTime)
|
||||
}
|
||||
cmd = executeCommand(config.Options, result.Binary, flags...)
|
||||
} else {
|
||||
// Run in an emulator.
|
||||
args := append(emulator[1:], result.Binary)
|
||||
if emulator[0] == "wasmtime" {
|
||||
// create a new temp directory just for this run, announce it to os.TempDir() via TMPDIR
|
||||
tmpdir, err := ioutil.TempDir("", "tinygotmp")
|
||||
if err != nil {
|
||||
return false, &commandError{"failed to create temporary directory", "tinygotmp", err}
|
||||
}
|
||||
args = append(args, "--dir="+tmpdir, "--env=TMPDIR="+tmpdir)
|
||||
// TODO: add option to not delete temp dir for debugging?
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
// allow reading from directories up to module root
|
||||
for _, d := range dirsToModuleRoot(result.MainDir, result.ModuleRoot) {
|
||||
args = append(args, "--dir="+d)
|
||||
}
|
||||
|
||||
// mark end of wasmtime arguments and start of program ones: --
|
||||
args = append(args, "--")
|
||||
if testVerbose {
|
||||
args = append(args, "-test.v")
|
||||
}
|
||||
if testShort {
|
||||
args = append(args, "-test.short")
|
||||
}
|
||||
if testRunRegexp != "" {
|
||||
args = append(args, "-test.run="+testRunRegexp)
|
||||
}
|
||||
if testBenchRegexp != "" {
|
||||
args = append(args, "-test.bench="+testBenchRegexp)
|
||||
}
|
||||
}
|
||||
cmd = executeCommand(config.Options, emulator[0], args...)
|
||||
}
|
||||
cmd.Dir = result.MainDir
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
if _, ok := err.(*exec.ExitError); ok {
|
||||
// Binary exited with a non-zero exit code, which means the test
|
||||
// failed.
|
||||
return false, nil
|
||||
}
|
||||
return false, &commandError{"failed to run compiled binary", result.Binary, err}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Flash builds and flashes the built binary to the given serial port.
|
||||
func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
config, err := builder.NewConfig(options)
|
||||
@@ -453,7 +422,11 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
args = append(args, "-c", "program "+filepath.ToSlash(result.Binary)+" reset exit")
|
||||
exit := " reset exit"
|
||||
if config.Target.OpenOCDVerify != nil && *config.Target.OpenOCDVerify {
|
||||
exit = " verify" + exit
|
||||
}
|
||||
args = append(args, "-c", "program "+filepath.ToSlash(result.Binary)+exit)
|
||||
cmd := executeCommand(config.Options, "openocd", args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
@@ -510,18 +483,19 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
|
||||
return err
|
||||
}
|
||||
|
||||
return builder.Build(pkgName, "", config, func(result builder.BuildResult) error {
|
||||
format, fileExt := config.EmulatorFormat()
|
||||
return builder.Build(pkgName, fileExt, config, func(result builder.BuildResult) error {
|
||||
// Find a good way to run GDB.
|
||||
gdbInterface, openocdInterface := config.Programmer()
|
||||
switch gdbInterface {
|
||||
case "msd", "command", "":
|
||||
emulator := config.Emulator()
|
||||
if len(emulator) != 0 {
|
||||
if emulator[0] == "mgba" {
|
||||
emulator := config.EmulatorName()
|
||||
if emulator != "" {
|
||||
if emulator == "mgba" {
|
||||
gdbInterface = "mgba"
|
||||
} else if emulator[0] == "simavr" {
|
||||
} else if emulator == "simavr" {
|
||||
gdbInterface = "simavr"
|
||||
} else if strings.HasPrefix(emulator[0], "qemu-system-") {
|
||||
} else if strings.HasPrefix(emulator, "qemu-system-") {
|
||||
gdbInterface = "qemu"
|
||||
} else {
|
||||
// Assume QEMU as an emulator.
|
||||
@@ -540,6 +514,10 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
|
||||
port := ""
|
||||
var gdbCommands []string
|
||||
var daemon *exec.Cmd
|
||||
emulator, err := config.Emulator(format, result.Binary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch gdbInterface {
|
||||
case "native":
|
||||
// Run GDB directly.
|
||||
@@ -589,33 +567,29 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
|
||||
}
|
||||
case "qemu":
|
||||
port = ":1234"
|
||||
emulator := config.Emulator()
|
||||
// Run in an emulator.
|
||||
args := append(emulator[1:], result.Binary, "-s", "-S")
|
||||
args := append(emulator[1:], "-s", "-S")
|
||||
daemon = executeCommand(config.Options, emulator[0], args...)
|
||||
daemon.Stdout = os.Stdout
|
||||
daemon.Stderr = os.Stderr
|
||||
case "qemu-user":
|
||||
port = ":1234"
|
||||
emulator := config.Emulator()
|
||||
// Run in an emulator.
|
||||
args := append(emulator[1:], "-g", "1234", result.Binary)
|
||||
args := append(emulator[1:], "-g", "1234")
|
||||
daemon = executeCommand(config.Options, emulator[0], args...)
|
||||
daemon.Stdout = os.Stdout
|
||||
daemon.Stderr = os.Stderr
|
||||
case "mgba":
|
||||
port = ":2345"
|
||||
emulator := config.Emulator()
|
||||
// Run in an emulator.
|
||||
args := append(emulator[1:], result.Binary, "-g")
|
||||
args := append(emulator[1:], "-g")
|
||||
daemon = executeCommand(config.Options, emulator[0], args...)
|
||||
daemon.Stdout = os.Stdout
|
||||
daemon.Stderr = os.Stderr
|
||||
case "simavr":
|
||||
port = ":1234"
|
||||
emulator := config.Emulator()
|
||||
// Run in an emulator.
|
||||
args := append(emulator[1:], "-g", result.Binary)
|
||||
args := append(emulator[1:], "-g")
|
||||
daemon = executeCommand(config.Options, emulator[0], args...)
|
||||
daemon.Stdout = os.Stdout
|
||||
daemon.Stderr = os.Stderr
|
||||
@@ -660,7 +634,7 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
|
||||
// Construct and execute a gdb or lldb command.
|
||||
// By default: gdb -ex run <binary>
|
||||
// Exit the debugger with Ctrl-D.
|
||||
params := []string{result.Binary}
|
||||
params := []string{result.Executable}
|
||||
switch debugger {
|
||||
case "gdb":
|
||||
if port != "" {
|
||||
@@ -692,9 +666,9 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return &commandError{"failed to run " + cmdName + " with", result.Binary, err}
|
||||
return &commandError{"failed to run " + cmdName + " with", result.Executable, err}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -704,44 +678,134 @@ func Debug(debugger, pkgName string, ocdOutput bool, options *compileopts.Option
|
||||
// the options, it will run the program directly on the host or will run it in
|
||||
// an emulator. For example, -target=wasm will cause the binary to be run inside
|
||||
// of a WebAssembly VM.
|
||||
func Run(pkgName string, options *compileopts.Options) error {
|
||||
func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error {
|
||||
config, err := builder.NewConfig(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return builder.Build(pkgName, ".elf", config, func(result builder.BuildResult) error {
|
||||
emulator := config.Emulator()
|
||||
if len(emulator) == 0 {
|
||||
// Run directly.
|
||||
cmd := executeCommand(config.Options, result.Binary)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
if err, ok := err.(*exec.ExitError); ok && err.Exited() {
|
||||
// Workaround for QEMU which always exits with an error.
|
||||
return nil
|
||||
}
|
||||
return &commandError{"failed to run compiled binary", result.Binary, err}
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
// Run in an emulator.
|
||||
args := append(emulator[1:], result.Binary)
|
||||
cmd := executeCommand(config.Options, emulator[0], args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
if err, ok := err.(*exec.ExitError); ok && err.Exited() {
|
||||
// Workaround for QEMU which always exits with an error.
|
||||
return nil
|
||||
}
|
||||
return &commandError{"failed to run emulator with", result.Binary, err}
|
||||
}
|
||||
return nil
|
||||
return buildAndRun(pkgName, config, os.Stdout, cmdArgs, nil, 0, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
return cmd.Run()
|
||||
})
|
||||
}
|
||||
|
||||
// buildAndRun builds and runs the given program, writing output to stdout and
|
||||
// errors to os.Stderr. It takes care of emulators (qemu, wasmtime, etc) and
|
||||
// passes command line arguments and evironment variables in a way appropriate
|
||||
// for the given emulator.
|
||||
func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, cmdArgs, environmentVars []string, timeout time.Duration, run func(cmd *exec.Cmd, result builder.BuildResult) error) error {
|
||||
// Determine whether we're on a system that supports environment variables
|
||||
// and command line parameters (operating systems, WASI) or not (baremetal,
|
||||
// WebAssembly in the browser). If we're on a system without an environment,
|
||||
// we need to pass command line arguments and environment variables through
|
||||
// global variables (built into the binary directly) instead of the
|
||||
// conventional way.
|
||||
needsEnvInVars := config.GOOS() == "js"
|
||||
for _, tag := range config.BuildTags() {
|
||||
if tag == "baremetal" {
|
||||
needsEnvInVars = true
|
||||
}
|
||||
}
|
||||
var args, env []string
|
||||
if needsEnvInVars {
|
||||
runtimeGlobals := make(map[string]string)
|
||||
if len(cmdArgs) != 0 {
|
||||
runtimeGlobals["osArgs"] = strings.Join(cmdArgs, "\x00")
|
||||
}
|
||||
if len(environmentVars) != 0 {
|
||||
runtimeGlobals["osEnv"] = strings.Join(environmentVars, "\x00")
|
||||
}
|
||||
if len(runtimeGlobals) != 0 {
|
||||
// This sets the global variables like they would be set with
|
||||
// `-ldflags="-X=runtime.osArgs=first\x00second`.
|
||||
// The runtime package has two variables (osArgs and osEnv) that are
|
||||
// both strings, from which the parameters and environment variables
|
||||
// are read.
|
||||
config.Options.GlobalValues = map[string]map[string]string{
|
||||
"runtime": runtimeGlobals,
|
||||
}
|
||||
}
|
||||
} else if config.EmulatorName() == "wasmtime" {
|
||||
// Wasmtime needs some special flags to pass environment variables
|
||||
// and allow reading from the current directory.
|
||||
args = append(args, "--dir=.")
|
||||
for _, v := range environmentVars {
|
||||
args = append(args, "--env", v)
|
||||
}
|
||||
if len(cmdArgs) != 0 {
|
||||
// mark end of wasmtime arguments and start of program ones: --
|
||||
args = append(args, "--")
|
||||
args = append(args, cmdArgs...)
|
||||
}
|
||||
} else {
|
||||
// Pass environment variables and command line parameters as usual.
|
||||
// This also works on qemu-aarch64 etc.
|
||||
args = cmdArgs
|
||||
env = environmentVars
|
||||
}
|
||||
|
||||
format, fileExt := config.EmulatorFormat()
|
||||
return builder.Build(pkgName, fileExt, config, func(result builder.BuildResult) error {
|
||||
// If needed, set a timeout on the command. This is done in tests so
|
||||
// they don't waste resources on a stalled test.
|
||||
var ctx context.Context
|
||||
if timeout != 0 {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(context.Background(), timeout)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
// Set up the command.
|
||||
var name string
|
||||
if config.Target.Emulator == "" {
|
||||
name = result.Binary
|
||||
} else {
|
||||
emulator, err := config.Emulator(format, result.Binary)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name = emulator[0]
|
||||
emuArgs := append([]string(nil), emulator[1:]...)
|
||||
args = append(emuArgs, args...)
|
||||
}
|
||||
var cmd *exec.Cmd
|
||||
if ctx != nil {
|
||||
cmd = exec.CommandContext(ctx, name, args...)
|
||||
} else {
|
||||
cmd = exec.Command(name, args...)
|
||||
}
|
||||
cmd.Env = env
|
||||
|
||||
// Configure stdout/stderr. The stdout may go to a buffer, not a real
|
||||
// stdout.
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
if config.EmulatorName() == "simavr" {
|
||||
cmd.Stdout = nil // don't print initial load commands
|
||||
cmd.Stderr = stdout
|
||||
}
|
||||
|
||||
// If this is a test, reserve CPU time for it so that increased
|
||||
// parallelism doesn't blow up memory usage. If this isn't a test but
|
||||
// simply `tinygo run`, then it is practically a no-op.
|
||||
config.Options.Semaphore <- struct{}{}
|
||||
defer func() {
|
||||
<-config.Options.Semaphore
|
||||
}()
|
||||
|
||||
// Run binary.
|
||||
if config.Options.PrintCommands != nil {
|
||||
config.Options.PrintCommands(cmd.Path, cmd.Args...)
|
||||
}
|
||||
err := run(cmd, result)
|
||||
if err != nil {
|
||||
if ctx != nil && ctx.Err() == context.DeadlineExceeded {
|
||||
stdout.Write([]byte(fmt.Sprintf("--- timeout of %s exceeded, terminating...\n", timeout)))
|
||||
err = ctx.Err()
|
||||
}
|
||||
return &commandError{"failed to run compiled binary", result.Binary, err}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1407,13 +1471,13 @@ func main() {
|
||||
handleCompilerError(err)
|
||||
}
|
||||
case "run":
|
||||
if flag.NArg() != 1 {
|
||||
if flag.NArg() < 1 {
|
||||
fmt.Fprintln(os.Stderr, "No package specified.")
|
||||
usage(command)
|
||||
os.Exit(1)
|
||||
}
|
||||
pkgName := filepath.ToSlash(flag.Arg(0))
|
||||
err := Run(pkgName, options)
|
||||
err := Run(pkgName, options, flag.Args()[1:])
|
||||
handleCompilerError(err)
|
||||
case "test":
|
||||
var pkgNames []string
|
||||
@@ -1509,7 +1573,7 @@ func main() {
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == nil {
|
||||
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
|
||||
|
||||
+15
-103
@@ -6,7 +6,6 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
@@ -14,7 +13,6 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
@@ -66,7 +64,6 @@ func TestBuild(t *testing.T) {
|
||||
"stdlib.go",
|
||||
"string.go",
|
||||
"structs.go",
|
||||
"testing.go",
|
||||
"zeroalloc.go",
|
||||
}
|
||||
_, minor, err := goenv.GetGorootVersion(goenv.Get("GOROOT"))
|
||||
@@ -76,6 +73,11 @@ func TestBuild(t *testing.T) {
|
||||
if minor >= 17 {
|
||||
tests = append(tests, "go1.17.go")
|
||||
}
|
||||
if minor >= 18 {
|
||||
tests = append(tests, "testing_go118.go")
|
||||
} else {
|
||||
tests = append(tests, "testing.go")
|
||||
}
|
||||
|
||||
if *testTarget != "" {
|
||||
// This makes it possible to run one specific test (instead of all),
|
||||
@@ -221,7 +223,7 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
runTest(name, options, t, nil, nil)
|
||||
})
|
||||
}
|
||||
if len(spec.Emulator) == 0 || spec.Emulator[0] != "simavr" {
|
||||
if !strings.HasPrefix(spec.Emulator, "simavr ") {
|
||||
t.Run("env.go", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
runTest("env.go", options, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
|
||||
@@ -255,8 +257,8 @@ func emuCheck(t *testing.T, options compileopts.Options) {
|
||||
if err != nil {
|
||||
t.Fatal("failed to load target spec:", err)
|
||||
}
|
||||
if len(spec.Emulator) != 0 {
|
||||
_, err := exec.LookPath(spec.Emulator[0])
|
||||
if spec.Emulator != "" {
|
||||
_, err := exec.LookPath(strings.SplitN(spec.Emulator, " ", 2)[0])
|
||||
if err != nil {
|
||||
if errors.Is(err, exec.ErrNotFound) {
|
||||
t.Skipf("emulator not installed: %q", spec.Emulator[0])
|
||||
@@ -320,117 +322,27 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
t.Fatal("could not read expected output file:", err)
|
||||
}
|
||||
|
||||
// Create a temporary directory for test output files.
|
||||
tmpdir := t.TempDir()
|
||||
|
||||
// Determine whether we're on a system that supports environment variables
|
||||
// and command line parameters (operating systems, WASI) or not (baremetal,
|
||||
// WebAssembly in the browser). If we're on a system without an environment,
|
||||
// we need to pass command line arguments and environment variables through
|
||||
// global variables (built into the binary directly) instead of the
|
||||
// conventional way.
|
||||
spec, err := compileopts.LoadTarget(&options)
|
||||
config, err := builder.NewConfig(&options)
|
||||
if err != nil {
|
||||
t.Fatal("failed to load target spec:", err)
|
||||
}
|
||||
needsEnvInVars := spec.GOOS == "js"
|
||||
for _, tag := range spec.BuildTags {
|
||||
if tag == "baremetal" {
|
||||
needsEnvInVars = true
|
||||
}
|
||||
}
|
||||
if needsEnvInVars {
|
||||
runtimeGlobals := make(map[string]string)
|
||||
if len(cmdArgs) != 0 {
|
||||
runtimeGlobals["osArgs"] = strings.Join(cmdArgs, "\x00")
|
||||
}
|
||||
if len(environmentVars) != 0 {
|
||||
runtimeGlobals["osEnv"] = strings.Join(environmentVars, "\x00")
|
||||
}
|
||||
if len(runtimeGlobals) != 0 {
|
||||
// This sets the global variables like they would be set with
|
||||
// `-ldflags="-X=runtime.osArgs=first\x00second`.
|
||||
// The runtime package has two variables (osArgs and osEnv) that are
|
||||
// both strings, from which the parameters and environment variables
|
||||
// are read.
|
||||
options.GlobalValues = map[string]map[string]string{
|
||||
"runtime": runtimeGlobals,
|
||||
}
|
||||
}
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Build the test binary.
|
||||
binary := filepath.Join(tmpdir, "test")
|
||||
if spec.GOOS == "windows" {
|
||||
binary += ".exe"
|
||||
}
|
||||
err = Build("./"+path, binary, &options)
|
||||
stdout := &bytes.Buffer{}
|
||||
err = buildAndRun("./"+path, config, stdout, cmdArgs, environmentVars, time.Minute, func(cmd *exec.Cmd, result builder.BuildResult) error {
|
||||
return cmd.Run()
|
||||
})
|
||||
if err != nil {
|
||||
printCompilerError(t.Log, err)
|
||||
t.Fail()
|
||||
return
|
||||
}
|
||||
|
||||
// Reserve CPU time for the test to run.
|
||||
// This attempts to ensure that the test is not CPU-starved.
|
||||
options.Semaphore <- struct{}{}
|
||||
defer func() { <-options.Semaphore }()
|
||||
|
||||
// Create the test command, taking care of emulators etc.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
var cmd *exec.Cmd
|
||||
|
||||
// make sure any special vars in the emulator definition are rewritten
|
||||
config := compileopts.Config{Target: spec}
|
||||
emulator := config.Emulator()
|
||||
|
||||
if len(emulator) == 0 {
|
||||
cmd = exec.CommandContext(ctx, binary)
|
||||
} else {
|
||||
args := append(emulator[1:], binary)
|
||||
cmd = exec.CommandContext(ctx, emulator[0], args...)
|
||||
}
|
||||
|
||||
if len(emulator) != 0 && emulator[0] == "wasmtime" {
|
||||
// Allow reading from the current directory.
|
||||
cmd.Args = append(cmd.Args, "--dir=.")
|
||||
for _, v := range environmentVars {
|
||||
cmd.Args = append(cmd.Args, "--env", v)
|
||||
}
|
||||
cmd.Args = append(cmd.Args, cmdArgs...)
|
||||
} else {
|
||||
if !needsEnvInVars {
|
||||
cmd.Args = append(cmd.Args, cmdArgs...) // works on qemu-aarch64 etc
|
||||
cmd.Env = append(cmd.Env, environmentVars...)
|
||||
}
|
||||
}
|
||||
|
||||
// Run the test.
|
||||
stdout := &bytes.Buffer{}
|
||||
if len(emulator) != 0 && emulator[0] == "simavr" {
|
||||
cmd.Stdout = os.Stderr
|
||||
cmd.Stderr = stdout
|
||||
} else {
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
err = cmd.Start()
|
||||
if err != nil {
|
||||
t.Fatal("failed to start:", err)
|
||||
}
|
||||
err = cmd.Wait()
|
||||
|
||||
if cerr := ctx.Err(); cerr == context.DeadlineExceeded {
|
||||
stdout.WriteString("--- test ran too long, terminating...\n")
|
||||
err = cerr
|
||||
}
|
||||
|
||||
// putchar() prints CRLF, convert it to LF.
|
||||
actual := bytes.Replace(stdout.Bytes(), []byte{'\r', '\n'}, []byte{'\n'}, -1)
|
||||
expected = bytes.Replace(expected, []byte{'\r', '\n'}, []byte{'\n'}, -1) // for Windows
|
||||
|
||||
if len(emulator) != 0 && emulator[0] == "simavr" {
|
||||
if config.EmulatorName() == "simavr" {
|
||||
// Strip simavr log formatting.
|
||||
actual = bytes.Replace(actual, []byte{0x1b, '[', '3', '2', 'm'}, nil, -1)
|
||||
actual = bytes.Replace(actual, []byte{0x1b, '[', '0', 'm'}, nil, -1)
|
||||
|
||||
@@ -142,18 +142,14 @@ func (mpu *MPU_Type) Enable(enable bool) {
|
||||
if enable {
|
||||
mpu.CTRL.Set(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk)
|
||||
SystemControl.SHCSR.SetBits(SCB_SHCSR_MEMFAULTENA_Msk)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
arm.Asm("isb 0xF")
|
||||
enableDcache(true)
|
||||
enableIcache(true)
|
||||
} else {
|
||||
enableIcache(false)
|
||||
enableDcache(false)
|
||||
arm.AsmFull(`
|
||||
dmb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dmb 0xF")
|
||||
SystemControl.SHCSR.ClearBits(SCB_SHCSR_MEMFAULTENA_Msk)
|
||||
mpu.CTRL.ClearBits(MPU_CTRL_ENABLE_Msk)
|
||||
}
|
||||
@@ -188,31 +184,21 @@ func (mpu *MPU_Type) SetRASR(size RegionSize, access AccessPerms, ext Extension,
|
||||
func enableIcache(enable bool) {
|
||||
if enable != SystemControl.CCR.HasBits(SCB_CCR_IC_Msk) {
|
||||
if enable {
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
arm.Asm("isb 0xF")
|
||||
SystemControl.ICIALLU.Set(0)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
arm.Asm("isb 0xF")
|
||||
SystemControl.CCR.SetBits(SCB_CCR_IC_Msk)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
arm.Asm("isb 0xF")
|
||||
} else {
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
arm.Asm("isb 0xF")
|
||||
SystemControl.CCR.ClearBits(SCB_CCR_IC_Msk)
|
||||
SystemControl.ICIALLU.Set(0)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
arm.Asm("isb 0xF")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -227,9 +213,7 @@ func enableDcache(enable bool) {
|
||||
if enable != SystemControl.CCR.HasBits(SCB_CCR_DC_Msk) {
|
||||
if enable {
|
||||
SystemControl.CSSELR.Set(0)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
ccsidr := SystemControl.CCSIDR.Get()
|
||||
sets := (ccsidr & SCB_CCSIDR_NUMSETS_Msk) >> SCB_CCSIDR_NUMSETS_Pos
|
||||
for sets != 0 {
|
||||
@@ -242,23 +226,15 @@ func enableDcache(enable bool) {
|
||||
}
|
||||
sets--
|
||||
}
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
SystemControl.CCR.SetBits(SCB_CCR_DC_Msk)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
arm.Asm("isb 0xF")
|
||||
} else {
|
||||
SystemControl.CSSELR.Set(0)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
SystemControl.CCR.ClearBits(SCB_CCR_DC_Msk)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
dcacheCcsidr.Set(SystemControl.CCSIDR.Get())
|
||||
dcacheSets.Set((dcacheCcsidr.Get() & SCB_CCSIDR_NUMSETS_Msk) >> SCB_CCSIDR_NUMSETS_Pos)
|
||||
for dcacheSets.Get() != 0 {
|
||||
@@ -271,10 +247,8 @@ func enableDcache(enable bool) {
|
||||
}
|
||||
dcacheSets.Set(dcacheSets.Get() - 1)
|
||||
}
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
arm.Asm("dsb 0xF")
|
||||
arm.Asm("isb 0xF")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
// Reads multiple rp2040 ADC channels concurrently. Including the internal temperature sensor
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
type celsius float32
|
||||
|
||||
func (c celsius) String() string {
|
||||
return fmt.Sprintf("%4.1f℃", c)
|
||||
}
|
||||
|
||||
// rp2040 ADC is 12 bits. Reading are shifted <<4 to fill the 16-bit range.
|
||||
var adcReading [3]uint16
|
||||
|
||||
func readADC(a machine.ADC, w time.Duration, i int) {
|
||||
for {
|
||||
adcReading[i] = a.Get()
|
||||
time.Sleep(w)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
machine.InitADC()
|
||||
a0 := machine.ADC{machine.ADC0} // GPIO26 input
|
||||
a1 := machine.ADC{machine.ADC1} // GPIO27 input
|
||||
a2 := machine.ADC{machine.ADC2} // GPIO28 input
|
||||
t := machine.ADC_TEMP_SENSOR // Internal Temperature sensor
|
||||
// Configure sets the GPIOs to PinAnalog mode
|
||||
a0.Configure(machine.ADCConfig{})
|
||||
a1.Configure(machine.ADCConfig{})
|
||||
a2.Configure(machine.ADCConfig{})
|
||||
// Configure powers on the temperature sensor
|
||||
t.Configure(machine.ADCConfig{})
|
||||
|
||||
// Safe to read concurrently
|
||||
go readADC(a0, 10*time.Millisecond, 0)
|
||||
go readADC(a1, 17*time.Millisecond, 1)
|
||||
go readADC(a2, 29*time.Millisecond, 2)
|
||||
|
||||
for {
|
||||
fmt.Printf("ADC0: %5d ADC1: %5d ADC2: %5d Temp: %v\n\r", adcReading[0], adcReading[1], adcReading[2], celsius(float32(t.ReadTemperature())/1000))
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
// Package fuzz is a shim to allow compilation against Go 1.18.
|
||||
// It only defines a single type to work with testing/internal/testdeps,
|
||||
// and hide all the other new dependencies from this package.
|
||||
package fuzz
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CorpusEntry represents an individual input for fuzzing.
|
||||
//
|
||||
// We must use an equivalent type in the testing and testing/internal/testdeps
|
||||
// packages, but testing can't import this package directly, and we don't want
|
||||
// to export this type from testing. Instead, we use the same struct type and
|
||||
// use a type alias (not a defined type) for convenience.
|
||||
type CorpusEntry = struct {
|
||||
Parent string
|
||||
|
||||
// Path is the path of the corpus file, if the entry was loaded from disk.
|
||||
// For other entries, including seed values provided by f.Add, Path is the
|
||||
// name of the test, e.g. seed#0 or its hash.
|
||||
Path string
|
||||
|
||||
// Data is the raw input data. Data should only be populated for seed
|
||||
// values. For on-disk corpus files, Data will be nil, as it will be loaded
|
||||
// from disk using Path.
|
||||
Data []byte
|
||||
|
||||
// Values is the unmarshaled values from a corpus file.
|
||||
Values []any
|
||||
|
||||
Generation int
|
||||
|
||||
// IsSeed indicates whether this entry is part of the seed corpus.
|
||||
IsSeed bool
|
||||
}
|
||||
|
||||
// CoordinateFuzzingOpts is a set of arguments for CoordinateFuzzing.
|
||||
// The zero value is valid for each field unless specified otherwise.
|
||||
type CoordinateFuzzingOpts struct {
|
||||
// Log is a writer for logging progress messages and warnings.
|
||||
// If nil, io.Discard will be used instead.
|
||||
Log io.Writer
|
||||
|
||||
// Timeout is the amount of wall clock time to spend fuzzing after the corpus
|
||||
// has loaded. If zero, there will be no time limit.
|
||||
Timeout time.Duration
|
||||
|
||||
// Limit is the number of random values to generate and test. If zero,
|
||||
// there will be no limit on the number of generated values.
|
||||
Limit int64
|
||||
|
||||
// MinimizeTimeout is the amount of wall clock time to spend minimizing
|
||||
// after discovering a crasher. If zero, there will be no time limit. If
|
||||
// MinimizeTimeout and MinimizeLimit are both zero, then minimization will
|
||||
// be disabled.
|
||||
MinimizeTimeout time.Duration
|
||||
|
||||
// MinimizeLimit is the maximum number of calls to the fuzz function to be
|
||||
// made while minimizing after finding a crash. If zero, there will be no
|
||||
// limit. Calls to the fuzz function made when minimizing also count toward
|
||||
// Limit. If MinimizeTimeout and MinimizeLimit are both zero, then
|
||||
// minimization will be disabled.
|
||||
MinimizeLimit int64
|
||||
|
||||
// parallel is the number of worker processes to run in parallel. If zero,
|
||||
// CoordinateFuzzing will run GOMAXPROCS workers.
|
||||
Parallel int
|
||||
|
||||
// Seed is a list of seed values added by the fuzz target with testing.F.Add
|
||||
// and in testdata.
|
||||
Seed []CorpusEntry
|
||||
|
||||
// Types is the list of types which make up a corpus entry.
|
||||
// Types must be set and must match values in Seed.
|
||||
Types []reflect.Type
|
||||
|
||||
// CorpusDir is a directory where files containing values that crash the
|
||||
// code being tested may be written. CorpusDir must be set.
|
||||
CorpusDir string
|
||||
|
||||
// CacheDir is a directory containing additional "interesting" values.
|
||||
// The fuzzer may derive new values from these, and may write new values here.
|
||||
CacheDir string
|
||||
}
|
||||
|
||||
// CoordinateFuzzing creates several worker processes and communicates with
|
||||
// them to test random inputs that could trigger crashes and expose bugs.
|
||||
// The worker processes run the same binary in the same directory with the
|
||||
// same environment variables as the coordinator process. Workers also run
|
||||
// with the same arguments as the coordinator, except with the -test.fuzzworker
|
||||
// flag prepended to the argument list.
|
||||
//
|
||||
// If a crash occurs, the function will return an error containing information
|
||||
// about the crash, which can be reported to the user.
|
||||
func CoordinateFuzzing(ctx context.Context, opts CoordinateFuzzingOpts) (err error) {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
// ReadCorpus reads the corpus from the provided dir. The returned corpus
|
||||
// entries are guaranteed to match the given types. Any malformed files will
|
||||
// be saved in a MalformedCorpusError and returned, along with the most recent
|
||||
// error.
|
||||
func ReadCorpus(dir string, types []reflect.Type) ([]CorpusEntry, error) {
|
||||
return nil, errors.New("not implemented")
|
||||
}
|
||||
|
||||
// CheckCorpus verifies that the types in vals match the expected types
|
||||
// provided.
|
||||
func CheckCorpus(vals []any, types []reflect.Type) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func ResetCoverage() {}
|
||||
func SnapshotCoverage() {}
|
||||
|
||||
// RunFuzzWorker is called in a worker process to communicate with the
|
||||
// coordinator process in order to fuzz random inputs. RunFuzzWorker loops
|
||||
// until the coordinator tells it to stop.
|
||||
//
|
||||
// fn is a wrapper on the fuzz function. It may return an error to indicate
|
||||
// a given input "crashed". The coordinator will also record a crasher if
|
||||
// the function times out or terminates the process.
|
||||
//
|
||||
// RunFuzzWorker returns an error if it could not communicate with the
|
||||
// coordinator process.
|
||||
func RunFuzzWorker(ctx context.Context, fn func(CorpusEntry) error) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
@@ -42,6 +42,9 @@ const (
|
||||
SPIQ = IO17
|
||||
U0RXD = IO20
|
||||
U0TXD = IO21
|
||||
|
||||
UART_TX_PIN = U0TXD
|
||||
UART_RX_PIN = U0RXD
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
//go:build nrf52840 || circuitplay_bluefruit || reelboard || clue || itsybitsy_nrf52840
|
||||
// +build nrf52840 circuitplay_bluefruit reelboard clue itsybitsy_nrf52840
|
||||
|
||||
package machine
|
||||
|
||||
// Hardware pins
|
||||
const (
|
||||
P0_00 Pin = 0
|
||||
P0_01 Pin = 1
|
||||
P0_02 Pin = 2
|
||||
P0_03 Pin = 3
|
||||
P0_04 Pin = 4
|
||||
P0_05 Pin = 5
|
||||
P0_06 Pin = 6
|
||||
P0_07 Pin = 7
|
||||
P0_08 Pin = 8
|
||||
P0_09 Pin = 9
|
||||
P0_10 Pin = 10
|
||||
P0_11 Pin = 11
|
||||
P0_12 Pin = 12
|
||||
P0_13 Pin = 13
|
||||
P0_14 Pin = 14
|
||||
P0_15 Pin = 15
|
||||
P0_16 Pin = 16
|
||||
P0_17 Pin = 17
|
||||
P0_18 Pin = 18
|
||||
P0_19 Pin = 19
|
||||
P0_20 Pin = 20
|
||||
P0_21 Pin = 21
|
||||
P0_22 Pin = 22
|
||||
P0_23 Pin = 23
|
||||
P0_24 Pin = 24
|
||||
P0_25 Pin = 25
|
||||
P0_26 Pin = 26
|
||||
P0_27 Pin = 27
|
||||
P0_28 Pin = 28
|
||||
P0_29 Pin = 29
|
||||
P0_30 Pin = 30
|
||||
P0_31 Pin = 31
|
||||
P1_00 Pin = 32
|
||||
P1_01 Pin = 33
|
||||
P1_02 Pin = 34
|
||||
P1_03 Pin = 35
|
||||
P1_04 Pin = 36
|
||||
P1_05 Pin = 37
|
||||
P1_06 Pin = 38
|
||||
P1_07 Pin = 39
|
||||
P1_08 Pin = 40
|
||||
P1_09 Pin = 41
|
||||
P1_10 Pin = 42
|
||||
P1_11 Pin = 43
|
||||
P1_12 Pin = 44
|
||||
P1_13 Pin = 45
|
||||
P1_14 Pin = 46
|
||||
P1_15 Pin = 47
|
||||
)
|
||||
@@ -237,6 +237,8 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
// #==================================================================#
|
||||
// | SPI |
|
||||
// #===========#==========#===============#===========================#
|
||||
// | Interface | Hardware | Clock(Freq) | SDI/SDO/SCK/CS : Alt |
|
||||
// #===========#==========#===============#=================-=========#
|
||||
@@ -261,6 +263,70 @@ const (
|
||||
SPI3_CS_PIN = D36
|
||||
)
|
||||
|
||||
var (
|
||||
SPI0 = SPI1 // SPI0 is an alias of SPI1 (LPSPI4)
|
||||
SPI1 = &_SPI1
|
||||
_SPI1 = SPI{
|
||||
Bus: nxp.LPSPI4,
|
||||
muxSDI: muxSelect{ // D12 (PB1 [B0_01])
|
||||
mux: nxp.IOMUXC_LPSPI4_SDI_SELECT_INPUT_DAISY_GPIO_B0_01_ALT3,
|
||||
sel: &nxp.IOMUXC.LPSPI4_SDI_SELECT_INPUT,
|
||||
},
|
||||
muxSDO: muxSelect{ // D11 (PB2 [B0_02])
|
||||
mux: nxp.IOMUXC_LPSPI4_SDO_SELECT_INPUT_DAISY_GPIO_B0_02_ALT3,
|
||||
sel: &nxp.IOMUXC.LPSPI4_SDO_SELECT_INPUT,
|
||||
},
|
||||
muxSCK: muxSelect{ // D13 (PB3 [B0_03])
|
||||
mux: nxp.IOMUXC_LPSPI4_SCK_SELECT_INPUT_DAISY_GPIO_B0_03_ALT3,
|
||||
sel: &nxp.IOMUXC.LPSPI4_SCK_SELECT_INPUT,
|
||||
},
|
||||
muxCS: muxSelect{ // D10 (PB0 [B0_00])
|
||||
mux: nxp.IOMUXC_LPSPI4_PCS0_SELECT_INPUT_DAISY_GPIO_B0_00_ALT3,
|
||||
sel: &nxp.IOMUXC.LPSPI4_PCS0_SELECT_INPUT,
|
||||
},
|
||||
}
|
||||
SPI2 = &_SPI2
|
||||
_SPI2 = SPI{
|
||||
Bus: nxp.LPSPI3,
|
||||
muxSDI: muxSelect{ // D1 (PA2 [AD_B0_02])
|
||||
mux: nxp.IOMUXC_LPSPI3_SDI_SELECT_INPUT_DAISY_GPIO_AD_B0_02_ALT7,
|
||||
sel: &nxp.IOMUXC.LPSPI3_SDI_SELECT_INPUT,
|
||||
},
|
||||
muxSDO: muxSelect{ // D26 (PA30 [AD_B1_14])
|
||||
mux: nxp.IOMUXC_LPSPI3_SDO_SELECT_INPUT_DAISY_GPIO_AD_B1_14_ALT2,
|
||||
sel: &nxp.IOMUXC.LPSPI3_SDO_SELECT_INPUT,
|
||||
},
|
||||
muxSCK: muxSelect{ // D27 (PA31 [AD_B1_15])
|
||||
mux: nxp.IOMUXC_LPSPI3_SCK_SELECT_INPUT_DAISY_GPIO_AD_B1_15,
|
||||
sel: &nxp.IOMUXC.LPSPI3_SCK_SELECT_INPUT,
|
||||
},
|
||||
muxCS: muxSelect{ // D0 (PA3 [AD_B0_03])
|
||||
mux: nxp.IOMUXC_LPSPI3_PCS0_SELECT_INPUT_DAISY_GPIO_AD_B0_03_ALT7,
|
||||
sel: &nxp.IOMUXC.LPSPI3_PCS0_SELECT_INPUT,
|
||||
},
|
||||
}
|
||||
SPI3 = &_SPI3
|
||||
_SPI3 = SPI{
|
||||
Bus: nxp.LPSPI1,
|
||||
muxSDI: muxSelect{ // D34 (PC15 [SD_B0_03])
|
||||
mux: nxp.IOMUXC_LPSPI1_SDI_SELECT_INPUT_DAISY_GPIO_SD_B0_03_ALT4,
|
||||
sel: &nxp.IOMUXC.LPSPI1_SDI_SELECT_INPUT,
|
||||
},
|
||||
muxSDO: muxSelect{ // D35 (PC14 [SD_B0_02])
|
||||
mux: nxp.IOMUXC_LPSPI1_SDO_SELECT_INPUT_DAISY_GPIO_SD_B0_02_ALT4,
|
||||
sel: &nxp.IOMUXC.LPSPI1_SDO_SELECT_INPUT,
|
||||
},
|
||||
muxSCK: muxSelect{ // D37 (PC12 [SD_B0_00])
|
||||
mux: nxp.IOMUXC_LPSPI1_SCK_SELECT_INPUT_DAISY_GPIO_SD_B0_00_ALT4,
|
||||
sel: &nxp.IOMUXC.LPSPI1_SCK_SELECT_INPUT,
|
||||
},
|
||||
muxCS: muxSelect{ // D36 (PC13 [SD_B0_01])
|
||||
mux: nxp.IOMUXC_LPSPI1_PCS0_SELECT_INPUT_DAISY_GPIO_SD_B0_01_ALT4,
|
||||
sel: &nxp.IOMUXC.LPSPI1_PCS0_SELECT_INPUT,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
// #====================================================#
|
||||
// | I2C |
|
||||
// #===========#==========#=============#===============#
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
//go:build thingplus_rp2040
|
||||
// +build thingplus_rp2040
|
||||
|
||||
package machine
|
||||
|
||||
const (
|
||||
LED = GPIO25
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
xoscFreq = 12 // MHz
|
||||
)
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
GP0 Pin = GPIO0 // TX
|
||||
GP1 Pin = GPIO1 // RX
|
||||
GP2 Pin = GPIO2 // SCK
|
||||
GP3 Pin = GPIO3 // COPI
|
||||
GP4 Pin = GPIO4 // CIPO
|
||||
|
||||
GP6 Pin = GPIO6 // SDA
|
||||
GP7 Pin = GPIO7 // SCL (connected to GPIO23 as well)
|
||||
GP8 Pin = GPIO8 // WS2812 RGB LED
|
||||
GP9 Pin = GPIO9 // muSDcard DATA3 / CS
|
||||
GP10 Pin = GPIO10 // muSDcard DATA2
|
||||
GP11 Pin = GPIO11 // muSDcard DATA1
|
||||
GP12 Pin = GPIO12 // muSDcard DATA0 / CIPO
|
||||
|
||||
GP14 Pin = GPIO14 // muSDcard CLK /SCLK
|
||||
GP15 Pin = GPIO15 // muSDcard CMD / COPI
|
||||
GP16 Pin = GPIO16 // 16
|
||||
GP17 Pin = GPIO17 // 17
|
||||
GP18 Pin = GPIO18 // 18
|
||||
GP19 Pin = GPIO19 // 19
|
||||
GP20 Pin = GPIO20 // 20
|
||||
GP21 Pin = GPIO21 // 21
|
||||
GP22 Pin = GPIO22 // 22
|
||||
GP23 Pin = GPIO23 // Connected to GPIO7
|
||||
GP25 Pin = GPIO25 // Status blue LED
|
||||
GP26 Pin = GPIO26 // ADC0
|
||||
GP27 Pin = GPIO27 // ADC1
|
||||
GP28 Pin = GPIO28 // ADC2
|
||||
GP29 Pin = GPIO29 // ADC3
|
||||
)
|
||||
|
||||
// Analog pins
|
||||
const (
|
||||
A0 = GPIO26
|
||||
A1 = GPIO27
|
||||
A2 = GPIO28
|
||||
A3 = GPIO29
|
||||
)
|
||||
|
||||
// I2C Pins.
|
||||
const (
|
||||
I2C0_SCL_PIN = GPIO6 // N/A
|
||||
I2C0_SDA_PIN = GPIO7 // N/A
|
||||
|
||||
I2C1_SDA_PIN = GPIO6
|
||||
I2C1_SCL_PIN = GPIO7
|
||||
|
||||
SDA_PIN = I2C1_SDA_PIN
|
||||
SCL_PIN = I2C1_SCL_PIN
|
||||
)
|
||||
|
||||
// SPI default pins
|
||||
const (
|
||||
// Default Serial Clock Bus 0 for SPI communications
|
||||
SPI0_SCK_PIN = GPIO2
|
||||
// Default Serial Out Bus 0 for SPI communications
|
||||
SPI0_SDO_PIN = GPIO3 // Tx
|
||||
// Default Serial In Bus 0 for SPI communications
|
||||
SPI0_SDI_PIN = GPIO4 // Rx
|
||||
|
||||
// Default Serial Clock Bus 1 for SPI communications to muSDcard
|
||||
SPI1_SCK_PIN = GPIO14
|
||||
// Default Serial Out Bus 1 for SPI communications to muSDcard
|
||||
SPI1_SDO_PIN = GPIO15 // Tx
|
||||
// Default Serial In Bus 1 for SPI communications to muSDcard
|
||||
SPI1_SDI_PIN = GPIO12 // Rx
|
||||
)
|
||||
@@ -0,0 +1,113 @@
|
||||
//go:build xiao_ble
|
||||
// +build xiao_ble
|
||||
|
||||
// This file contains the pin mappings for the Seeed XIAO BLE nRF52840 [Sense] boards.
|
||||
//
|
||||
// Seeed XIAO BLE is an ultra-small size, ultra-low power Bluetooth development board based on the Nordic nRF52840.
|
||||
// It features an onboard Bluetooth antenna, onboard battery charging chip, and 21*17.5mm thumb size, which makes it ideal for IoT projects.
|
||||
//
|
||||
// Seeed XIAO BLE nRF52840 Sense is a tiny Bluetooth LE development board designed for IoT and AI applications.
|
||||
// It features an onboard antenna, 6 Dof IMU, microphone, all of which make it an ideal board to run AI using TinyML and TensorFlow Lite.
|
||||
//
|
||||
// SoftDevice (s140v7) is pre-flashed on this board already.
|
||||
// See https://github.com/tinygo-org/bluetooth
|
||||
//
|
||||
// - https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html
|
||||
// - https://www.seeedstudio.com/Seeed-XIAO-BLE-Sense-nRF52840-p-5253.html
|
||||
//
|
||||
// - https://wiki.seeedstudio.com/XIAO_BLE/
|
||||
// - https://github.com/Seeed-Studio/ArduinoCore-mbed/tree/master/variants/SEEED_XIAO_NRF52840_SENSE
|
||||
//
|
||||
package machine
|
||||
|
||||
const HasLowFrequencyCrystal = true
|
||||
|
||||
// Digital Pins
|
||||
const (
|
||||
D0 Pin = P0_02
|
||||
D1 Pin = P0_03
|
||||
D2 Pin = P0_28
|
||||
D3 Pin = P0_29
|
||||
D4 Pin = P0_04
|
||||
D5 Pin = P0_05
|
||||
D6 Pin = P1_11
|
||||
D7 Pin = P1_12
|
||||
D8 Pin = P1_13
|
||||
D9 Pin = P1_14
|
||||
D10 Pin = P1_15
|
||||
)
|
||||
|
||||
// Analog pins
|
||||
const (
|
||||
A0 Pin = P0_02
|
||||
A1 Pin = P0_03
|
||||
A2 Pin = P0_28
|
||||
A3 Pin = P0_29
|
||||
A4 Pin = P0_04
|
||||
A5 Pin = P0_05
|
||||
)
|
||||
|
||||
// Onboard LEDs
|
||||
const (
|
||||
LED = LED_CHG
|
||||
LED1 = LED_RED
|
||||
LED2 = LED_GREEN
|
||||
LED3 = LED_BLUE
|
||||
LED_CHG = P0_17
|
||||
LED_RED = P0_26
|
||||
LED_GREEN = P0_30
|
||||
LED_BLUE = P0_06
|
||||
)
|
||||
|
||||
// UART0 pins
|
||||
const (
|
||||
UART_RX_PIN = P1_12
|
||||
UART_TX_PIN = P1_11
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
// Defaults to internal
|
||||
SDA_PIN = SDA1_PIN
|
||||
SCL_PIN = SCL1_PIN
|
||||
|
||||
// I2C0 (external) pins
|
||||
SDA0_PIN = P0_04
|
||||
SCL0_PIN = P0_05
|
||||
|
||||
// I2C1 (internal) pins
|
||||
SDA1_PIN = P0_07
|
||||
SCL1_PIN = P0_27
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI0_SCK_PIN = P1_13
|
||||
SPI0_SDO_PIN = P1_14
|
||||
SPI0_SDI_PIN = P1_15
|
||||
)
|
||||
|
||||
// Peripherals
|
||||
const (
|
||||
LSM_PWR = P1_08 // IMU (LSM6DS3TR) power
|
||||
LSM_INT = P0_11 // IMU (LSM6DS3TR) interrupt
|
||||
|
||||
MIC_PWR = P1_10 // Microphone (MSM261D3526H1CPM) power
|
||||
MIC_CLK = P1_00
|
||||
MIC_DIN = P0_16
|
||||
)
|
||||
|
||||
// USB CDC identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "XIAO nRF52840 Sense"
|
||||
usb_STRING_MANUFACTURER = "Seeed"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x2886
|
||||
usb_PID uint16 = 0x0045
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultUART = UART0
|
||||
)
|
||||
@@ -5,6 +5,8 @@ package machine
|
||||
|
||||
import (
|
||||
"device/esp"
|
||||
"device/riscv"
|
||||
"errors"
|
||||
"runtime/interrupt"
|
||||
"runtime/volatile"
|
||||
"sync"
|
||||
@@ -214,18 +216,269 @@ func setupPinInterrupt() error {
|
||||
}).Enable()
|
||||
}
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
var (
|
||||
DefaultUART = UART0
|
||||
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()}
|
||||
UART1 = &_UART1
|
||||
_UART1 = UART{Bus: esp.UART1, Buffer: NewRingBuffer()}
|
||||
|
||||
onceUart = sync.Once{}
|
||||
errSamePins = errors.New("UART: invalid pin combination")
|
||||
errWrongUART = errors.New("UART: unsupported UARTn")
|
||||
errWrongBitSize = errors.New("UART: invalid data size")
|
||||
errWrongStopBitSize = errors.New("UART: invalid bit size")
|
||||
)
|
||||
|
||||
type UART struct {
|
||||
Bus *esp.UART_Type
|
||||
Buffer *RingBuffer
|
||||
Bus *esp.UART_Type
|
||||
Buffer *RingBuffer
|
||||
ParityErrorDetected bool // set when parity error detected
|
||||
DataErrorDetected bool // set when data corruption detected
|
||||
DataOverflowDetected bool // set when data overflow detected in UART FIFO buffer or RingBuffer
|
||||
}
|
||||
|
||||
type UARTStopBits int
|
||||
|
||||
const (
|
||||
UARTStopBits_Default UARTStopBits = iota
|
||||
UARTStopBits_1
|
||||
UARTStopBits_1_5
|
||||
UARTStopBits_2
|
||||
)
|
||||
|
||||
const (
|
||||
defaultDataBits = 8
|
||||
defaultStopBit = 1
|
||||
defaultParity = ParityNone
|
||||
|
||||
uartInterrupts = esp.UART_INT_ENA_RXFIFO_FULL_INT_ENA |
|
||||
esp.UART_INT_ENA_PARITY_ERR_INT_ENA |
|
||||
esp.UART_INT_ENA_FRM_ERR_INT_ENA |
|
||||
esp.UART_INT_ENA_RXFIFO_OVF_INT_ENA |
|
||||
esp.UART_INT_ENA_GLITCH_DET_INT_ENA
|
||||
|
||||
pplClockFreq = 80e6
|
||||
)
|
||||
|
||||
type registerSet struct {
|
||||
interruptMapReg *volatile.Register32
|
||||
uartClockBitMask uint32
|
||||
gpioMatrixSignal uint32
|
||||
}
|
||||
|
||||
func (uart *UART) Configure(config UARTConfig) error {
|
||||
if config.BaudRate == 0 {
|
||||
config.BaudRate = 115200
|
||||
}
|
||||
if config.TX == config.RX {
|
||||
return errSamePins
|
||||
}
|
||||
switch {
|
||||
case uart.Bus == esp.UART0:
|
||||
return uart.configure(config, registerSet{
|
||||
interruptMapReg: &esp.INTERRUPT_CORE0.UART_INTR_MAP,
|
||||
uartClockBitMask: esp.SYSTEM_PERIP_CLK_EN0_UART_CLK_EN,
|
||||
gpioMatrixSignal: 6,
|
||||
})
|
||||
case uart.Bus == esp.UART1:
|
||||
return uart.configure(config, registerSet{
|
||||
interruptMapReg: &esp.INTERRUPT_CORE0.UART1_INTR_MAP,
|
||||
uartClockBitMask: esp.SYSTEM_PERIP_CLK_EN0_UART1_CLK_EN,
|
||||
gpioMatrixSignal: 9,
|
||||
})
|
||||
}
|
||||
return errWrongUART
|
||||
}
|
||||
|
||||
func (uart *UART) configure(config UARTConfig, regs registerSet) error {
|
||||
|
||||
initUARTClock(uart.Bus, regs)
|
||||
|
||||
// - disbale TX/RX clock to make sure the UART transmitter or receiver is not at work during configuration
|
||||
uart.Bus.SetCLK_CONF_TX_SCLK_EN(0)
|
||||
uart.Bus.SetCLK_CONF_RX_SCLK_EN(0)
|
||||
|
||||
// Configure static registers (Ref: Configuring URATn Communication)
|
||||
|
||||
// - default clock source: 1=APB_CLK, 2=FOSC_CLK, 3=XTAL_CLK
|
||||
uart.Bus.SetCLK_CONF_SCLK_SEL(1)
|
||||
// reset divisor of the divider via UART_SCLK_DIV_NUM, UART_SCLK_DIV_A, and UART_SCLK_DIV_B
|
||||
uart.Bus.SetCLK_CONF_SCLK_DIV_NUM(0)
|
||||
uart.Bus.SetCLK_CONF_SCLK_DIV_A(0)
|
||||
uart.Bus.SetCLK_CONF_SCLK_DIV_B(0)
|
||||
|
||||
// - the baud rate
|
||||
uart.SetBaudRate(config.BaudRate)
|
||||
// - the data format
|
||||
uart.SetFormat(defaultDataBits, defaultStopBit, defaultParity)
|
||||
// - set UART mode
|
||||
uart.Bus.SetRS485_CONF_RS485_EN(0)
|
||||
uart.Bus.SetRS485_CONF_RS485TX_RX_EN(0)
|
||||
uart.Bus.SetRS485_CONF_RS485RXBY_TX_EN(0)
|
||||
uart.Bus.SetCONF0_IRDA_EN(0)
|
||||
// - disable hw-flow control
|
||||
uart.Bus.SetCONF0_TX_FLOW_EN(0)
|
||||
uart.Bus.SetCONF1_RX_FLOW_EN(0)
|
||||
|
||||
// synchronize values into Core Clock
|
||||
uart.Bus.SetID_REG_UPDATE(1)
|
||||
|
||||
uart.setupPins(config, regs)
|
||||
uart.configureInterrupt(regs.interruptMapReg)
|
||||
uart.enableTransmitter()
|
||||
uart.enableReceiver()
|
||||
|
||||
// Start TX/RX
|
||||
uart.Bus.SetCLK_CONF_TX_SCLK_EN(1)
|
||||
uart.Bus.SetCLK_CONF_RX_SCLK_EN(1)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uart *UART) SetFormat(dataBits, stopBits int, parity UARTParity) error {
|
||||
if dataBits < 5 {
|
||||
return errWrongBitSize
|
||||
}
|
||||
if stopBits > 1 {
|
||||
return errWrongStopBitSize
|
||||
}
|
||||
// - data length
|
||||
uart.Bus.SetCONF0_BIT_NUM(uint32(dataBits - 5))
|
||||
// - stop bit
|
||||
uart.Bus.SetCONF0_STOP_BIT_NUM(uint32(stopBits))
|
||||
// - parity check
|
||||
switch parity {
|
||||
case ParityNone:
|
||||
uart.Bus.SetCONF0_PARITY_EN(0)
|
||||
case ParityEven:
|
||||
uart.Bus.SetCONF0_PARITY_EN(1)
|
||||
uart.Bus.SetCONF0_PARITY(0)
|
||||
case ParityOdd:
|
||||
uart.Bus.SetCONF0_PARITY_EN(1)
|
||||
uart.Bus.SetCONF0_PARITY(1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func initUARTClock(bus *esp.UART_Type, regs registerSet) {
|
||||
uartClock := &esp.SYSTEM.PERIP_CLK_EN0
|
||||
uartClockReset := &esp.SYSTEM.PERIP_RST_EN0
|
||||
|
||||
// Initialize/reset URATn (Ref: Initializing URATn)
|
||||
// - enable the clock for UART RAM
|
||||
uartClock.SetBits(esp.SYSTEM_PERIP_CLK_EN0_UART_MEM_CLK_EN)
|
||||
// - enable APB_CLK for UARTn
|
||||
uartClock.SetBits(regs.uartClockBitMask)
|
||||
// - reset sequence
|
||||
uartClockReset.ClearBits(regs.uartClockBitMask)
|
||||
bus.SetCLK_CONF_RST_CORE(1)
|
||||
uartClockReset.SetBits(regs.uartClockBitMask)
|
||||
uartClockReset.ClearBits(regs.uartClockBitMask)
|
||||
bus.SetCLK_CONF_RST_CORE(0)
|
||||
// synchronize core register
|
||||
bus.SetID_REG_UPDATE(0)
|
||||
// enable RTC clock
|
||||
esp.RTC_CNTL.SetRTC_CLK_CONF_DIG_CLK8M_EN(1)
|
||||
// wait for Core Clock to ready for configuration
|
||||
for bus.GetID_REG_UPDATE() > 0 {
|
||||
riscv.Asm("nop")
|
||||
}
|
||||
}
|
||||
|
||||
func (uart *UART) SetBaudRate(baudRate uint32) {
|
||||
// based on esp-idf
|
||||
max_div := uint32((1 << 12) - 1)
|
||||
sclk_div := (pplClockFreq + (max_div * baudRate) - 1) / (max_div * baudRate)
|
||||
clk_div := (pplClockFreq << 4) / (baudRate * sclk_div)
|
||||
uart.Bus.SetCLKDIV(clk_div >> 4)
|
||||
uart.Bus.SetCLKDIV_FRAG(clk_div & 0xf)
|
||||
uart.Bus.SetCLK_CONF_SCLK_DIV_NUM(sclk_div - 1)
|
||||
}
|
||||
|
||||
func (uart *UART) setupPins(config UARTConfig, regs registerSet) {
|
||||
config.RX.Configure(PinConfig{Mode: PinInputPullup})
|
||||
config.TX.Configure(PinConfig{Mode: PinInputPullup})
|
||||
|
||||
// link TX with GPIO signal X (technical reference manual 5.10) (this is not interrupt signal!)
|
||||
config.TX.outFunc().Set(regs.gpioMatrixSignal)
|
||||
// link RX with GPIO signal X and route signals via GPIO matrix (GPIO_SIGn_IN_SEL 0x40)
|
||||
inFunc(regs.gpioMatrixSignal).Set(esp.GPIO_FUNC_IN_SEL_CFG_SIG_IN_SEL | uint32(config.RX))
|
||||
}
|
||||
|
||||
func (uart *UART) configureInterrupt(intrMapReg *volatile.Register32) { // Disable all UART interrupts
|
||||
// Disable all UART interrupts
|
||||
uart.Bus.INT_ENA.ClearBits(0x0ffff)
|
||||
|
||||
intrMapReg.Set(7)
|
||||
onceUart.Do(func() {
|
||||
_ = interrupt.New(7, func(i interrupt.Interrupt) {
|
||||
UART0.serveInterrupt(0)
|
||||
UART1.serveInterrupt(1)
|
||||
}).Enable()
|
||||
})
|
||||
}
|
||||
|
||||
func (uart *UART) serveInterrupt(num int) {
|
||||
// get interrupt status
|
||||
interrutFlag := uart.Bus.INT_ST.Get()
|
||||
if (interrutFlag & uartInterrupts) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// block UART interrupts while processing
|
||||
uart.Bus.INT_ENA.ClearBits(uartInterrupts)
|
||||
|
||||
if interrutFlag&esp.UART_INT_ENA_RXFIFO_FULL_INT_ENA > 0 {
|
||||
for uart.Bus.GetSTATUS_RXFIFO_CNT() > 0 {
|
||||
b := uart.Bus.GetFIFO_RXFIFO_RD_BYTE()
|
||||
if !uart.Buffer.Put(byte(b & 0xff)) {
|
||||
uart.DataOverflowDetected = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if interrutFlag&esp.UART_INT_ENA_PARITY_ERR_INT_ENA > 0 {
|
||||
uart.ParityErrorDetected = true
|
||||
}
|
||||
if 0 != interrutFlag&esp.UART_INT_ENA_FRM_ERR_INT_ENA {
|
||||
uart.DataErrorDetected = true
|
||||
}
|
||||
if 0 != interrutFlag&esp.UART_INT_ENA_RXFIFO_OVF_INT_ENA {
|
||||
uart.DataOverflowDetected = true
|
||||
}
|
||||
if 0 != interrutFlag&esp.UART_INT_ENA_GLITCH_DET_INT_ENA {
|
||||
uart.DataErrorDetected = true
|
||||
}
|
||||
|
||||
// Clear the UART interrupt status
|
||||
uart.Bus.INT_CLR.SetBits(interrutFlag)
|
||||
uart.Bus.INT_CLR.ClearBits(interrutFlag)
|
||||
// Enable interrupts
|
||||
uart.Bus.INT_ENA.Set(uartInterrupts)
|
||||
}
|
||||
|
||||
const uart_empty_thresh_default = 10
|
||||
|
||||
func (uart *UART) enableTransmitter() {
|
||||
uart.Bus.SetCONF0_TXFIFO_RST(1)
|
||||
uart.Bus.SetCONF0_TXFIFO_RST(0)
|
||||
// TXINFO empty threshold is when txfifo_empty_int interrupt produced after the amount of data in Tx-FIFO is less than this register value.
|
||||
uart.Bus.SetCONF1_TXFIFO_EMPTY_THRHD(uart_empty_thresh_default)
|
||||
// we are not using interrut on TX since write we are waiting for FIFO to have space.
|
||||
// uart.Bus.INT_ENA.SetBits(esp.UART_INT_ENA_TXFIFO_EMPTY_INT_ENA)
|
||||
}
|
||||
|
||||
func (uart *UART) enableReceiver() {
|
||||
uart.Bus.SetCONF0_RXFIFO_RST(1)
|
||||
uart.Bus.SetCONF0_RXFIFO_RST(0)
|
||||
// using value 1 so that we can start populate ring buffer with data as we get it
|
||||
uart.Bus.SetCONF1_RXFIFO_FULL_THRHD(1)
|
||||
// enable interrupts for:
|
||||
uart.Bus.SetINT_ENA_RXFIFO_FULL_INT_ENA(1)
|
||||
uart.Bus.SetINT_ENA_FRM_ERR_INT_ENA(1)
|
||||
uart.Bus.SetINT_ENA_PARITY_ERR_INT_ENA(1)
|
||||
uart.Bus.SetINT_ENA_GLITCH_DET_INT_ENA(1)
|
||||
uart.Bus.SetINT_ENA_RXFIFO_OVF_INT_ENA(1)
|
||||
}
|
||||
|
||||
func (uart *UART) WriteByte(b byte) error {
|
||||
|
||||
@@ -236,10 +236,10 @@ func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
|
||||
kendryte.GPIOHS.RISE_IE.ClearBits(1 << pin)
|
||||
// Acknowledge interrupt atomically.
|
||||
riscv.AsmFull(
|
||||
"amoor.w {}, {mask}, {reg}",
|
||||
"amoor.w {}, {mask}, ({reg})",
|
||||
map[string]interface{}{
|
||||
"mask": uint32(1 << pin),
|
||||
"reg": &kendryte.GPIOHS.RISE_IP.Reg,
|
||||
"reg": uintptr(unsafe.Pointer(&kendryte.GPIOHS.RISE_IP.Reg)),
|
||||
})
|
||||
kendryte.GPIOHS.RISE_IE.SetBits(1 << pin)
|
||||
}
|
||||
@@ -248,10 +248,10 @@ func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
|
||||
kendryte.GPIOHS.FALL_IE.ClearBits(1 << pin)
|
||||
// Acknowledge interrupt atomically.
|
||||
riscv.AsmFull(
|
||||
"amoor.w {}, {mask}, {reg}",
|
||||
"amoor.w {}, {mask}, ({reg})",
|
||||
map[string]interface{}{
|
||||
"mask": uint32(1 << pin),
|
||||
"reg": &kendryte.GPIOHS.FALL_IP.Reg,
|
||||
"reg": uintptr(unsafe.Pointer(&kendryte.GPIOHS.FALL_IP.Reg)),
|
||||
})
|
||||
kendryte.GPIOHS.FALL_IE.SetBits(1 << pin)
|
||||
}
|
||||
|
||||
@@ -883,3 +883,179 @@ func (p Pin) getMuxMode(config PinConfig) uint32 {
|
||||
panic("machine: invalid pin mode")
|
||||
}
|
||||
}
|
||||
|
||||
// maximum ADC value for the currently configured resolution (used for scaling)
|
||||
var adcMaximum uint32
|
||||
|
||||
// InitADC is not used by this machine. Use `(ADC).Configure()`.
|
||||
func InitADC() {}
|
||||
|
||||
// Configure initializes the receiver's ADC peripheral and pin for analog input.
|
||||
func (a ADC) Configure(config ADCConfig) {
|
||||
// if not specified, use defaults: 10-bit resolution, 4 samples/conversion
|
||||
const (
|
||||
defaultResolution = uint32(10)
|
||||
defaultSamples = uint32(4)
|
||||
)
|
||||
|
||||
a.Pin.Configure(PinConfig{Mode: PinInputAnalog})
|
||||
|
||||
resolution, samples := config.Resolution, config.Samples
|
||||
if 0 == resolution {
|
||||
resolution = defaultResolution
|
||||
}
|
||||
if 0 == samples {
|
||||
samples = defaultSamples
|
||||
}
|
||||
if resolution > 12 {
|
||||
resolution = 12 // maximum resolution of 12 bits
|
||||
}
|
||||
adcMaximum = (uint32(1) << resolution) - 1
|
||||
|
||||
mode, average := a.mode(resolution, samples)
|
||||
|
||||
nxp.ADC1.CFG.Set(mode | nxp.ADC_CFG_ADHSC) // configure ADC1
|
||||
nxp.ADC2.CFG.Set(mode | nxp.ADC_CFG_ADHSC) // configure ADC2
|
||||
|
||||
// begin calibration
|
||||
nxp.ADC1.GC.Set(average | nxp.ADC_GC_CAL)
|
||||
nxp.ADC2.GC.Set(average | nxp.ADC_GC_CAL)
|
||||
|
||||
for a.isCalibrating() {
|
||||
} // wait for calibration
|
||||
}
|
||||
|
||||
// Get performs a single ADC conversion, returning a 16-bit unsigned integer.
|
||||
// The value returned will be scaled (uniformly distributed) if necessary so
|
||||
// that it is always in the range [0..65535], regardless of the ADC's configured
|
||||
// bit size (resolution).
|
||||
func (a ADC) Get() uint16 {
|
||||
if ch1, ch2, ok := a.Pin.getADCChannel(); ok {
|
||||
for a.isCalibrating() {
|
||||
} // wait for calibration
|
||||
var val uint32
|
||||
if noADCChannel != ch1 {
|
||||
nxp.ADC1.HC0.Set(uint32(ch1))
|
||||
for !nxp.ADC1.HS.HasBits(nxp.ADC_HS_COCO0) {
|
||||
}
|
||||
val = nxp.ADC1.R0.Get() & 0xFFFF
|
||||
} else {
|
||||
nxp.ADC2.HC0.Set(uint32(ch2))
|
||||
for !nxp.ADC2.HS.HasBits(nxp.ADC_HS_COCO0) {
|
||||
}
|
||||
val = nxp.ADC2.R0.Get() & 0xFFFF
|
||||
}
|
||||
// should never be zero, but just in case, use UINT16_MAX so that the scalar
|
||||
// gets factored out of the conversion result, leaving the original reading
|
||||
// to be returned unaltered/unscaled.
|
||||
if adcMaximum == 0 {
|
||||
adcMaximum = 0xFFFF
|
||||
}
|
||||
// scale up to a 16-bit value
|
||||
return uint16((val * 0xFFFF) / adcMaximum)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// mode constructs bit masks for mode and average - used in ADC configuration
|
||||
// registers - from a given ADC bit size (resolution) and sample count.
|
||||
func (a ADC) mode(resolution, samples uint32) (mode, average uint32) {
|
||||
|
||||
// use asynchronous clock (ADACK) (0 = IPG, 1 = IPG/2, or 3 = ADACK)
|
||||
mode = (nxp.ADC_CFG_ADICLK_ADICLK_3 << nxp.ADC_CFG_ADICLK_Pos) & nxp.ADC_CFG_ADICLK_Msk
|
||||
|
||||
// input clock DIV2 (0 = DIV1, 1 = DIV2, 2 = DIV4, or 3 = DIV8)
|
||||
mode |= (nxp.ADC_CFG_ADIV_ADIV_1 << nxp.ADC_CFG_ADIV_Pos) & nxp.ADC_CFG_ADIV_Msk
|
||||
|
||||
switch resolution {
|
||||
case 8: // 8-bit conversion, sample period (ADC clocks) = 8
|
||||
mode |= (nxp.ADC_CFG_MODE_MODE_0 << nxp.ADC_CFG_MODE_Pos) & nxp.ADC_CFG_MODE_Msk
|
||||
mode |= (nxp.ADC_CFG_ADSTS_ADSTS_3 << nxp.ADC_CFG_ADSTS_Pos) & nxp.ADC_CFG_ADSTS_Msk
|
||||
|
||||
case 12: // 12-bit conversion, sample period (ADC clocks) = 24
|
||||
mode |= (nxp.ADC_CFG_MODE_MODE_2 << nxp.ADC_CFG_MODE_Pos) & nxp.ADC_CFG_MODE_Msk
|
||||
mode |= (nxp.ADC_CFG_ADSTS_ADSTS_3 << nxp.ADC_CFG_ADSTS_Pos) & nxp.ADC_CFG_ADSTS_Msk
|
||||
mode |= nxp.ADC_CFG_ADLSMP
|
||||
|
||||
default: // 10-bit conversion, sample period (ADC clocks) = 20
|
||||
mode |= (nxp.ADC_CFG_MODE_MODE_1 << nxp.ADC_CFG_MODE_Pos) & nxp.ADC_CFG_MODE_Msk
|
||||
mode |= (nxp.ADC_CFG_ADSTS_ADSTS_2 << nxp.ADC_CFG_ADSTS_Pos) & nxp.ADC_CFG_ADSTS_Msk
|
||||
mode |= nxp.ADC_CFG_ADLSMP
|
||||
}
|
||||
|
||||
if samples >= 4 {
|
||||
if samples >= 32 {
|
||||
// 32 samples averaged
|
||||
mode |= (nxp.ADC_CFG_AVGS_AVGS_3 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk
|
||||
} else if samples >= 16 {
|
||||
// 16 samples averaged
|
||||
mode |= (nxp.ADC_CFG_AVGS_AVGS_2 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk
|
||||
} else if samples >= 8 {
|
||||
// 8 samples averaged
|
||||
mode |= (nxp.ADC_CFG_AVGS_AVGS_1 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk
|
||||
} else {
|
||||
// 4 samples averaged
|
||||
mode |= (nxp.ADC_CFG_AVGS_AVGS_0 << nxp.ADC_CFG_AVGS_Pos) & nxp.ADC_CFG_AVGS_Msk
|
||||
}
|
||||
average = nxp.ADC_GC_AVGE
|
||||
}
|
||||
|
||||
return mode, average
|
||||
}
|
||||
|
||||
// isCalibrating returns true if and only if either one (or both) of ADC1 and
|
||||
// ADC2 have their calibrating flags set. ADC reads must wait until these flags
|
||||
// are clear before attempting a conversion.
|
||||
func (a ADC) isCalibrating() bool {
|
||||
return nxp.ADC1.GC.HasBits(nxp.ADC_GC_CAL) || nxp.ADC2.GC.HasBits(nxp.ADC_GC_CAL)
|
||||
}
|
||||
|
||||
const noADCChannel = uint8(0xFF)
|
||||
|
||||
// getADCChannel returns the input channel for ADC1/ADC2 of the receiver Pin p.
|
||||
func (p Pin) getADCChannel() (adc1, adc2 uint8, ok bool) {
|
||||
switch p {
|
||||
case PA12: // [AD_B0_12]: ADC1_IN1 ~
|
||||
return 1, noADCChannel, true
|
||||
case PA13: // [AD_B0_13]: ADC1_IN2 ~
|
||||
return 2, noADCChannel, true
|
||||
case PA14: // [AD_B0_14]: ADC1_IN3 ~
|
||||
return 3, noADCChannel, true
|
||||
case PA15: // [AD_B0_15]: ADC1_IN4 ~
|
||||
return 4, noADCChannel, true
|
||||
case PA16: // [AD_B1_00]: ADC1_IN5 ADC2_IN5
|
||||
return 5, 5, true
|
||||
case PA17: // [AD_B1_01]: ADC1_IN6 ADC2_IN6
|
||||
return 6, 6, true
|
||||
case PA18: // [AD_B1_02]: ADC1_IN7 ADC2_IN7
|
||||
return 7, 7, true
|
||||
case PA19: // [AD_B1_03]: ADC1_IN8 ADC2_IN8
|
||||
return 8, 8, true
|
||||
case PA20: // [AD_B1_04]: ADC1_IN9 ADC2_IN9
|
||||
return 9, 9, true
|
||||
case PA21: // [AD_B1_05]: ADC1_IN10 ADC2_IN10
|
||||
return 10, 10, true
|
||||
case PA22: // [AD_B1_06]: ADC1_IN11 ADC2_IN11
|
||||
return 11, 11, true
|
||||
case PA23: // [AD_B1_07]: ADC1_IN12 ADC2_IN12
|
||||
return 12, 12, true
|
||||
case PA24: // [AD_B1_08]: ADC1_IN13 ADC2_IN13
|
||||
return 13, 13, true
|
||||
case PA25: // [AD_B1_09]: ADC1_IN14 ADC2_IN14
|
||||
return 14, 14, true
|
||||
case PA26: // [AD_B1_10]: ADC1_IN15 ADC2_IN15
|
||||
return 15, 15, true
|
||||
case PA27: // [AD_B1_11]: ADC1_IN0 ADC2_IN0
|
||||
return 16, 16, true
|
||||
case PA28: // [AD_B1_12]: ~ ADC2_IN1
|
||||
return noADCChannel, 1, true
|
||||
case PA29: // [AD_B1_13]: ~ ADC2_IN2
|
||||
return noADCChannel, 2, true
|
||||
case PA30: // [AD_B1_14]: ~ ADC2_IN3
|
||||
return noADCChannel, 3, true
|
||||
case PA31: // [AD_B1_15]: ~ ADC2_IN4
|
||||
return noADCChannel, 4, true
|
||||
default:
|
||||
return noADCChannel, noADCChannel, false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
//go:build mimxrt1062
|
||||
// +build mimxrt1062
|
||||
|
||||
package machine
|
||||
|
||||
// SPI peripheral abstraction layer for the MIMXRT1062
|
||||
|
||||
import (
|
||||
"device/nxp"
|
||||
"errors"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// SPIConfig is used to store config info for SPI.
|
||||
type SPIConfig struct {
|
||||
Frequency uint32
|
||||
SDI Pin
|
||||
SDO Pin
|
||||
SCK Pin
|
||||
CS Pin
|
||||
LSBFirst bool
|
||||
Mode uint8
|
||||
}
|
||||
|
||||
func (c SPIConfig) getPins() (di, do, ck, cs Pin) {
|
||||
if 0 == c.SDI && 0 == c.SDO && 0 == c.SCK && 0 == c.CS {
|
||||
// default pins if none specified
|
||||
return SPI_SDI_PIN, SPI_SDO_PIN, SPI_SCK_PIN, SPI_CS_PIN
|
||||
}
|
||||
return c.SDI, c.SDO, c.SCK, c.CS
|
||||
}
|
||||
|
||||
type SPI struct {
|
||||
Bus *nxp.LPSPI_Type
|
||||
|
||||
// these hold the input selector ("daisy chain") values that select which pins
|
||||
// are connected to the LPSPI device, and should be defined where the SPI
|
||||
// instance is declared (e.g., in the board definition). see the godoc
|
||||
// comments on type muxSelect for more details.
|
||||
muxSDI, muxSDO, muxSCK, muxCS muxSelect
|
||||
|
||||
// these are copied from SPIConfig, during (*SPI).Configure(SPIConfig), and
|
||||
// should be considered read-only for internal reference (i.e., modifying them
|
||||
// will have no desirable effect).
|
||||
sdi, sdo, sck, cs Pin
|
||||
frequency uint32
|
||||
|
||||
// auxiliary state data used internally
|
||||
configured bool
|
||||
}
|
||||
|
||||
const (
|
||||
statusTxDataRequest = nxp.LPSPI_SR_TDF // Transmit data flag
|
||||
statusRxDataReady = nxp.LPSPI_SR_RDF // Receive data flag
|
||||
statusWordComplete = nxp.LPSPI_SR_WCF // Word Complete flag
|
||||
statusFrameComplete = nxp.LPSPI_SR_FCF // Frame Complete flag
|
||||
statusTransferComplete = nxp.LPSPI_SR_TCF // Transfer Complete flag
|
||||
statusTransmitError = nxp.LPSPI_SR_TEF // Transmit Error flag (FIFO underrun)
|
||||
statusReceiveError = nxp.LPSPI_SR_REF // Receive Error flag (FIFO overrun)
|
||||
statusDataMatch = nxp.LPSPI_SR_DMF // Data Match flag
|
||||
statusModuleBusy = nxp.LPSPI_SR_MBF // Module Busy flag
|
||||
statusAll = nxp.LPSPI_SR_TDF | nxp.LPSPI_SR_RDF |
|
||||
nxp.LPSPI_SR_WCF | nxp.LPSPI_SR_FCF | nxp.LPSPI_SR_TCF | nxp.LPSPI_SR_TEF |
|
||||
nxp.LPSPI_SR_REF | nxp.LPSPI_SR_DMF | nxp.LPSPI_SR_MBF
|
||||
)
|
||||
|
||||
var (
|
||||
errSPINotConfigured = errors.New("SPI interface is not yet configured")
|
||||
)
|
||||
|
||||
// Configure is intended to setup an SPI interface for transmit/receive.
|
||||
func (spi *SPI) Configure(config SPIConfig) {
|
||||
|
||||
const defaultSpiFreq = 4000000 // 4 MHz
|
||||
|
||||
// init pins
|
||||
spi.sdi, spi.sdo, spi.sck, spi.cs = config.getPins()
|
||||
|
||||
// configure the mux and pad control registers
|
||||
spi.sdi.Configure(PinConfig{Mode: PinModeSPISDI})
|
||||
spi.sdo.Configure(PinConfig{Mode: PinModeSPISDO})
|
||||
spi.sck.Configure(PinConfig{Mode: PinModeSPICLK})
|
||||
spi.cs.Configure(PinConfig{Mode: PinModeSPICS})
|
||||
|
||||
// configure the mux input selector
|
||||
spi.muxSDI.connect()
|
||||
spi.muxSDO.connect()
|
||||
spi.muxSCK.connect()
|
||||
spi.muxCS.connect()
|
||||
|
||||
// software reset of LPSPI state registers
|
||||
spi.Bus.CR.SetBits(nxp.LPSPI_CR_RST)
|
||||
// also reset FIFOs (not performed by software reset above)
|
||||
spi.Bus.CR.SetBits(nxp.LPSPI_CR_RRF | nxp.LPSPI_CR_RTF)
|
||||
spi.Bus.CR.Set(0)
|
||||
|
||||
// set controller mode, and input data is sampled on delayed SCK edge
|
||||
spi.Bus.CFGR1.Set(nxp.LPSPI_CFGR1_MASTER | nxp.LPSPI_CFGR1_SAMPLE)
|
||||
|
||||
spi.frequency = config.Frequency
|
||||
if 0 == spi.frequency {
|
||||
spi.frequency = defaultSpiFreq
|
||||
}
|
||||
|
||||
// configure LPSPI clock divisor and CS assertion delays
|
||||
div := spi.getClockDivisor(config.Frequency)
|
||||
ccr := (div << nxp.LPSPI_CCR_SCKDIV_Pos) & nxp.LPSPI_CCR_SCKDIV_Msk
|
||||
ccr |= ((div / 2) << nxp.LPSPI_CCR_DBT_Pos) & nxp.LPSPI_CCR_DBT_Msk
|
||||
ccr |= ((div / 2) << nxp.LPSPI_CCR_PCSSCK_Pos) & nxp.LPSPI_CCR_PCSSCK_Msk
|
||||
spi.Bus.CCR.Set(ccr)
|
||||
|
||||
// 8-bit frame size (words)
|
||||
tcr := uint32(7)
|
||||
if config.LSBFirst {
|
||||
tcr |= nxp.LPSPI_TCR_LSBF
|
||||
}
|
||||
// set polarity and phase
|
||||
switch config.Mode {
|
||||
case Mode1:
|
||||
tcr |= nxp.LPSPI_TCR_CPHA
|
||||
case Mode2:
|
||||
tcr |= nxp.LPSPI_TCR_CPOL
|
||||
case Mode3:
|
||||
tcr |= nxp.LPSPI_TCR_CPOL
|
||||
tcr |= nxp.LPSPI_TCR_CPHA
|
||||
}
|
||||
spi.Bus.TCR.Set(tcr)
|
||||
|
||||
// clear FIFO water marks
|
||||
spi.setWatermark(0, 0)
|
||||
|
||||
// enable LPSPI module
|
||||
spi.Bus.CR.Set(nxp.LPSPI_CR_MEN)
|
||||
|
||||
spi.configured = true
|
||||
}
|
||||
|
||||
// Transfer writes/reads a single byte using the SPI interface.
|
||||
func (spi *SPI) Transfer(w byte) (byte, error) {
|
||||
if !spi.configured {
|
||||
return 0, errSPINotConfigured
|
||||
}
|
||||
|
||||
const readTryMax = 10000
|
||||
|
||||
for spi.Bus.SR.HasBits(statusModuleBusy) {
|
||||
} // wait for SPI busy bit to clear
|
||||
|
||||
_, txFIFOSize := spi.getFIFOSize()
|
||||
|
||||
spi.flushFIFO(true, true)
|
||||
spi.Bus.SR.Set(statusAll) // clear all status flags (W1C)
|
||||
|
||||
// enable LPSPI module
|
||||
spi.Bus.CR.Set(nxp.LPSPI_CR_MEN)
|
||||
|
||||
// TODO: unnecessary since we just flushed the FIFO?
|
||||
for { // wait for TX FIFO to not be full
|
||||
if _, txFIFO := spi.getFIFOCount(); txFIFO < txFIFOSize {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// write out byte to TX FIFO
|
||||
spi.Bus.TDR.Set(uint32(w))
|
||||
|
||||
// try to read from RX FIFO if anything exists
|
||||
didRead := false
|
||||
data := byte(0)
|
||||
for i := 0; !didRead && (i < readTryMax); i++ {
|
||||
rxFIFO, _ := spi.getFIFOCount()
|
||||
didRead = rxFIFO > 0
|
||||
if didRead {
|
||||
data = byte(spi.Bus.RDR.Get())
|
||||
}
|
||||
}
|
||||
|
||||
// if nothing was read, then wait for transfer complete flag to decide when
|
||||
// we are finished
|
||||
if !didRead {
|
||||
for !spi.Bus.SR.HasBits(nxp.LPSPI_SR_TCF) {
|
||||
} // wait for all transfers complete flag to set
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (spi *SPI) isHardwareCSPin(pin Pin) bool {
|
||||
switch unsafe.Pointer(spi.Bus) {
|
||||
case unsafe.Pointer(nxp.LPSPI1):
|
||||
return SPI1_CS_PIN == pin
|
||||
case unsafe.Pointer(nxp.LPSPI2):
|
||||
return SPI2_CS_PIN == pin
|
||||
case unsafe.Pointer(nxp.LPSPI3):
|
||||
return SPI3_CS_PIN == pin
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (spi *SPI) hasHardwareCSPin() bool {
|
||||
return spi.isHardwareCSPin(spi.cs)
|
||||
}
|
||||
|
||||
// getClockDivisor finds the SPI prescalar that minimizes the error between
|
||||
// requested frequency and possible frequencies available with the LPSPI clock.
|
||||
// this routine is based on Teensyduino (libraries/SPI/SPI.cpp):
|
||||
// `void SPIClass::setClockDivider_noInline(uint32_t clk)`
|
||||
func (spi *SPI) getClockDivisor(freq uint32) uint32 {
|
||||
const clock = 132000000 // LPSPI root clock frequency (PLL2)
|
||||
d := uint32(clock)
|
||||
if freq > 0 {
|
||||
d /= freq
|
||||
}
|
||||
if d > 0 && clock/d > freq {
|
||||
d++
|
||||
}
|
||||
if d > 257 {
|
||||
return 255
|
||||
}
|
||||
if d > 2 {
|
||||
return d - 2
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (spi *SPI) getFIFOSize() (rx, tx uint32) {
|
||||
param := spi.Bus.PARAM.Get()
|
||||
return uint32(1) << ((param & nxp.LPSPI_PARAM_RXFIFO_Msk) >> nxp.LPSPI_PARAM_RXFIFO_Pos),
|
||||
uint32(1) << ((param & nxp.LPSPI_PARAM_TXFIFO_Msk) >> nxp.LPSPI_PARAM_TXFIFO_Pos)
|
||||
}
|
||||
|
||||
func (spi *SPI) getFIFOCount() (rx, tx uint32) {
|
||||
fsr := spi.Bus.FSR.Get()
|
||||
return (fsr & nxp.LPSPI_FSR_RXCOUNT_Msk) >> nxp.LPSPI_FSR_RXCOUNT_Pos,
|
||||
(fsr & nxp.LPSPI_FSR_TXCOUNT_Msk) >> nxp.LPSPI_FSR_TXCOUNT_Pos
|
||||
}
|
||||
|
||||
func (spi *SPI) flushFIFO(rx, tx bool) {
|
||||
var flush uint32
|
||||
if rx {
|
||||
flush |= nxp.LPSPI_CR_RRF
|
||||
}
|
||||
if tx {
|
||||
flush |= nxp.LPSPI_CR_RTF
|
||||
}
|
||||
spi.Bus.CR.SetBits(flush)
|
||||
}
|
||||
|
||||
func (spi *SPI) setWatermark(rx, tx uint32) {
|
||||
spi.Bus.FCR.Set(((rx << nxp.LPSPI_FCR_RXWATER_Pos) & nxp.LPSPI_FCR_RXWATER_Msk) |
|
||||
((tx << nxp.LPSPI_FCR_TXWATER_Pos) & nxp.LPSPI_FCR_TXWATER_Msk))
|
||||
}
|
||||
@@ -7,58 +7,6 @@ import (
|
||||
"device/nrf"
|
||||
)
|
||||
|
||||
// Hardware pins
|
||||
const (
|
||||
P0_00 Pin = 0
|
||||
P0_01 Pin = 1
|
||||
P0_02 Pin = 2
|
||||
P0_03 Pin = 3
|
||||
P0_04 Pin = 4
|
||||
P0_05 Pin = 5
|
||||
P0_06 Pin = 6
|
||||
P0_07 Pin = 7
|
||||
P0_08 Pin = 8
|
||||
P0_09 Pin = 9
|
||||
P0_10 Pin = 10
|
||||
P0_11 Pin = 11
|
||||
P0_12 Pin = 12
|
||||
P0_13 Pin = 13
|
||||
P0_14 Pin = 14
|
||||
P0_15 Pin = 15
|
||||
P0_16 Pin = 16
|
||||
P0_17 Pin = 17
|
||||
P0_18 Pin = 18
|
||||
P0_19 Pin = 19
|
||||
P0_20 Pin = 20
|
||||
P0_21 Pin = 21
|
||||
P0_22 Pin = 22
|
||||
P0_23 Pin = 23
|
||||
P0_24 Pin = 24
|
||||
P0_25 Pin = 25
|
||||
P0_26 Pin = 26
|
||||
P0_27 Pin = 27
|
||||
P0_28 Pin = 28
|
||||
P0_29 Pin = 29
|
||||
P0_30 Pin = 30
|
||||
P0_31 Pin = 31
|
||||
P1_00 Pin = 32
|
||||
P1_01 Pin = 33
|
||||
P1_02 Pin = 34
|
||||
P1_03 Pin = 35
|
||||
P1_04 Pin = 36
|
||||
P1_05 Pin = 37
|
||||
P1_06 Pin = 38
|
||||
P1_07 Pin = 39
|
||||
P1_08 Pin = 40
|
||||
P1_09 Pin = 41
|
||||
P1_10 Pin = 42
|
||||
P1_11 Pin = 43
|
||||
P1_12 Pin = 44
|
||||
P1_13 Pin = 45
|
||||
P1_14 Pin = 46
|
||||
P1_15 Pin = 47
|
||||
)
|
||||
|
||||
// Get peripheral and pin number for this GPIO pin.
|
||||
func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
|
||||
if p >= 32 {
|
||||
|
||||
@@ -5,58 +5,142 @@ package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"errors"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ADCChannel is the ADC peripheral mux channel. 0-4.
|
||||
type ADCChannel uint8
|
||||
|
||||
// ADC channels. Only ADC_TEMP_SENSOR is public. The other channels are accessed via Machine.ADC objects
|
||||
const (
|
||||
adc0_CH ADCChannel = iota
|
||||
adc1_CH
|
||||
adc2_CH
|
||||
adc3_CH // Note: GPIO29 not broken out on pico board
|
||||
ADC_TEMP_SENSOR // Internal temperature sensor channel
|
||||
)
|
||||
|
||||
// Used to serialise ADC sampling
|
||||
var adcLock sync.Mutex
|
||||
|
||||
// ADC peripheral reference voltage (mV)
|
||||
var adcAref uint32
|
||||
|
||||
// InitADC resets the ADC peripheral.
|
||||
func InitADC() {
|
||||
// reset ADC
|
||||
rp.RESETS.RESET.SetBits(rp.RESETS_RESET_ADC)
|
||||
rp.RESETS.RESET.ClearBits(rp.RESETS_RESET_ADC)
|
||||
for !rp.RESETS.RESET_DONE.HasBits(rp.RESETS_RESET_ADC) {
|
||||
}
|
||||
|
||||
// enable ADC
|
||||
rp.ADC.CS.Set(rp.ADC_CS_EN)
|
||||
|
||||
adcAref = 3300
|
||||
waitForReady()
|
||||
}
|
||||
|
||||
// Configure configures a ADC pin to be able to be used to read data.
|
||||
func (a ADC) Configure(config ADCConfig) {
|
||||
switch a.Pin {
|
||||
case ADC0, ADC1, ADC2, ADC3:
|
||||
a.Pin.Configure(PinConfig{Mode: PinAnalog})
|
||||
default:
|
||||
// invalid ADC
|
||||
return
|
||||
// Configure sets the ADC pin to analog input mode.
|
||||
func (a ADC) Configure(config ADCConfig) error {
|
||||
c, err := a.GetADCChannel()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.Configure(config)
|
||||
}
|
||||
|
||||
// Get returns a one-shot ADC sample reading.
|
||||
func (a ADC) Get() uint16 {
|
||||
rp.ADC.CS.SetBits(uint32(a.getADCChannel()) << rp.ADC_CS_AINSEL_Pos)
|
||||
if c, err := a.GetADCChannel(); err == nil {
|
||||
return c.getOnce()
|
||||
}
|
||||
// Not an ADC pin!
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetADCChannel returns the channel associated with the ADC pin.
|
||||
func (a ADC) GetADCChannel() (c ADCChannel, err error) {
|
||||
err = nil
|
||||
switch a.Pin {
|
||||
case ADC0:
|
||||
c = adc0_CH
|
||||
case ADC1:
|
||||
c = adc1_CH
|
||||
case ADC2:
|
||||
c = adc2_CH
|
||||
case ADC3:
|
||||
c = adc3_CH
|
||||
default:
|
||||
err = errors.New("no ADC channel for pin value")
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
|
||||
// Configure sets the channel's associated pin to analog input mode or powers on the temperature sensor for ADC_TEMP_SENSOR.
|
||||
// The powered on temperature sensor increases ADC_AVDD current by approximately 40 μA.
|
||||
func (c ADCChannel) Configure(config ADCConfig) error {
|
||||
if config.Reference != 0 {
|
||||
adcAref = config.Reference
|
||||
}
|
||||
if p, err := c.Pin(); err == nil {
|
||||
p.Configure(PinConfig{Mode: PinAnalog})
|
||||
}
|
||||
if c == ADC_TEMP_SENSOR {
|
||||
// Enable temperature sensor bias source
|
||||
rp.ADC.CS.SetBits(rp.ADC_CS_TS_EN)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getOnce returns a one-shot ADC sample reading from an ADC channel.
|
||||
func (c ADCChannel) getOnce() uint16 {
|
||||
// Make it safe to sample multiple ADC channels in separate go routines.
|
||||
adcLock.Lock()
|
||||
rp.ADC.CS.ReplaceBits(uint32(c), 0b111, rp.ADC_CS_AINSEL_Pos)
|
||||
rp.ADC.CS.SetBits(rp.ADC_CS_START_ONCE)
|
||||
|
||||
waitForReady()
|
||||
adcLock.Unlock()
|
||||
|
||||
// rp2040 uses 12-bit sampling, so scale to 16-bit
|
||||
return uint16(rp.ADC.RESULT.Get() << 4)
|
||||
// rp2040 is a 12-bit ADC, scale raw reading to 16-bits.
|
||||
return uint16(rp.ADC.RESULT.Get()) << 4
|
||||
}
|
||||
|
||||
// getVoltage does a one-shot sample and returns a millivolts reading.
|
||||
// Integer portion is stored in the high 16 bits and fractional in the low 16 bits.
|
||||
func (c ADCChannel) getVoltage() uint32 {
|
||||
return (adcAref << 16) / (1 << 12) * uint32(c.getOnce()>>4)
|
||||
}
|
||||
|
||||
// ReadTemperature does a one-shot sample of the internal temperature sensor and returns a milli-celsius reading.
|
||||
// Only works on the ADC_TEMP_SENSOR channel. aka AINSEL=4. Other channels will return 0
|
||||
func (c ADCChannel) ReadTemperature() (millicelsius uint32) {
|
||||
if c != ADC_TEMP_SENSOR {
|
||||
return
|
||||
}
|
||||
// T = 27 - (ADC_voltage - 0.706)/0.001721
|
||||
return (27000<<16 - (c.getVoltage()-706<<16)*581) >> 16
|
||||
}
|
||||
|
||||
// waitForReady spins waiting for the ADC peripheral to become ready.
|
||||
func waitForReady() {
|
||||
for !rp.ADC.CS.HasBits(rp.ADC_CS_READY) {
|
||||
}
|
||||
}
|
||||
|
||||
func (a ADC) getADCChannel() uint8 {
|
||||
switch a.Pin {
|
||||
case ADC0:
|
||||
return 0
|
||||
case ADC1:
|
||||
return 1
|
||||
case ADC2:
|
||||
return 2
|
||||
case ADC3:
|
||||
return 3
|
||||
// The Pin method returns the GPIO Pin associated with the ADC mux channel, if it has one.
|
||||
func (c ADCChannel) Pin() (p Pin, err error) {
|
||||
err = nil
|
||||
switch c {
|
||||
case adc0_CH:
|
||||
p = ADC0
|
||||
case adc1_CH:
|
||||
p = ADC1
|
||||
case adc2_CH:
|
||||
p = ADC2
|
||||
case adc3_CH:
|
||||
p = ADC3
|
||||
default:
|
||||
return 0
|
||||
err = errors.New("no associated pin for channel")
|
||||
}
|
||||
return p, err
|
||||
}
|
||||
|
||||
@@ -74,19 +74,7 @@ var (
|
||||
func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
|
||||
// timeout in microseconds.
|
||||
const timeout = 40 * 1000 // 40ms is a reasonable time for a real-time system.
|
||||
if len(w) > 0 {
|
||||
if err := i2c.tx(uint8(addr), w, false, timeout); nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(r) > 0 {
|
||||
if err := i2c.rx(uint8(addr), r, false, timeout); nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return i2c.tx(uint8(addr), w, r, timeout)
|
||||
}
|
||||
|
||||
// Configure initializes i2c peripheral and configures I2C config's pins passed.
|
||||
@@ -239,16 +227,16 @@ func (i2c *I2C) deinit() (resetVal uint32) {
|
||||
return resetVal
|
||||
}
|
||||
|
||||
// tx is a primitive i2c blocking write to bus routine. timeout is time to wait
|
||||
// in microseconds since calling this function for write to finish.
|
||||
func (i2c *I2C) tx(addr uint8, tx []byte, nostop bool, timeout uint64) (err error) {
|
||||
deadline := ticks() + timeout
|
||||
// tx performs blocking write followed by read to I2C bus.
|
||||
func (i2c *I2C) tx(addr uint8, tx, rx []byte, timeout_us uint64) (err error) {
|
||||
deadline := ticks() + timeout_us
|
||||
if addr >= 0x80 || isReservedI2CAddr(addr) {
|
||||
return ErrInvalidTgtAddr
|
||||
}
|
||||
tlen := len(tx)
|
||||
txlen := len(tx)
|
||||
rxlen := len(rx)
|
||||
// Quick return if possible.
|
||||
if tlen == 0 {
|
||||
if txlen == 0 && rxlen == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -258,17 +246,18 @@ func (i2c *I2C) tx(addr uint8, tx []byte, nostop bool, timeout uint64) (err erro
|
||||
}
|
||||
i2c.Bus.IC_TAR.Set(uint32(addr))
|
||||
i2c.enable()
|
||||
// If no timeout was passed timeoutCheck is false.
|
||||
abort := false
|
||||
var abortReason uint32
|
||||
byteCtr := 0
|
||||
for ; byteCtr < tlen; byteCtr++ {
|
||||
first := byteCtr == 0
|
||||
last := byteCtr == tlen-1
|
||||
for txCtr := 0; txCtr < txlen; txCtr++ {
|
||||
if abort {
|
||||
break
|
||||
}
|
||||
first := txCtr == 0
|
||||
last := txCtr == txlen-1 && rxlen == 0
|
||||
i2c.Bus.IC_DATA_CMD.Set(
|
||||
(boolToBit(first && i2c.restartOnNext) << rp.I2C0_IC_DATA_CMD_RESTART_Pos) |
|
||||
(boolToBit(last && !nostop) << rp.I2C0_IC_DATA_CMD_STOP_Pos) |
|
||||
uint32(tx[byteCtr]))
|
||||
(boolToBit(last) << rp.I2C0_IC_DATA_CMD_STOP_Pos) |
|
||||
uint32(tx[txCtr]))
|
||||
|
||||
// Wait until the transmission of the address/data from the internal
|
||||
// shift register has completed. For this to function correctly, the
|
||||
@@ -288,7 +277,6 @@ func (i2c *I2C) tx(addr uint8, tx []byte, nostop bool, timeout uint64) (err erro
|
||||
// any activity, then with ic_en=0, this bit is set to 0.
|
||||
for !i2c.interrupted(rp.I2C0_IC_RAW_INTR_STAT_TX_EMPTY) {
|
||||
if ticks() > deadline {
|
||||
i2c.restartOnNext = nostop
|
||||
return errI2CWriteTimeout // If there was a timeout, don't attempt to do anything else.
|
||||
}
|
||||
}
|
||||
@@ -298,7 +286,7 @@ func (i2c *I2C) tx(addr uint8, tx []byte, nostop bool, timeout uint64) (err erro
|
||||
i2c.clearAbortReason()
|
||||
abort = true
|
||||
}
|
||||
if abort || (last && !nostop) {
|
||||
if abort || last {
|
||||
// If the transaction was aborted or if it completed
|
||||
// successfully wait until the STOP condition has occured.
|
||||
|
||||
@@ -307,7 +295,6 @@ func (i2c *I2C) tx(addr uint8, tx []byte, nostop bool, timeout uint64) (err erro
|
||||
// to take care of the abort.
|
||||
for !i2c.interrupted(rp.I2C0_IC_RAW_INTR_STAT_STOP_DET) {
|
||||
if ticks() > deadline {
|
||||
i2c.restartOnNext = nostop
|
||||
return errI2CWriteTimeout
|
||||
}
|
||||
}
|
||||
@@ -315,6 +302,33 @@ func (i2c *I2C) tx(addr uint8, tx []byte, nostop bool, timeout uint64) (err erro
|
||||
}
|
||||
}
|
||||
|
||||
if rxlen > 0 && !abort {
|
||||
for rxCtr := 0; rxCtr < rxlen; rxCtr++ {
|
||||
first := rxCtr == 0
|
||||
last := rxCtr == rxlen-1
|
||||
for i2c.writeAvailable() == 0 {
|
||||
}
|
||||
i2c.Bus.IC_DATA_CMD.Set(
|
||||
boolToBit(first && i2c.restartOnNext)<<rp.I2C0_IC_DATA_CMD_RESTART_Pos |
|
||||
boolToBit(last)<<rp.I2C0_IC_DATA_CMD_STOP_Pos |
|
||||
rp.I2C0_IC_DATA_CMD_CMD) // -> 1 for read
|
||||
|
||||
for !abort && i2c.readAvailable() == 0 {
|
||||
abortReason = i2c.getAbortReason()
|
||||
i2c.clearAbortReason()
|
||||
if abortReason != 0 {
|
||||
abort = true
|
||||
}
|
||||
if ticks() > deadline {
|
||||
return errI2CReadTimeout // If there was a timeout, don't attempt to do anything else.
|
||||
}
|
||||
}
|
||||
if abort {
|
||||
break
|
||||
}
|
||||
rx[rxCtr] = uint8(i2c.Bus.IC_DATA_CMD.Get())
|
||||
}
|
||||
}
|
||||
// From Pico SDK: A lot of things could have just happened due to the ingenious and
|
||||
// creative design of I2C. Try to figure things out.
|
||||
if abort {
|
||||
@@ -327,78 +341,9 @@ func (i2c *I2C) tx(addr uint8, tx []byte, nostop bool, timeout uint64) (err erro
|
||||
// Address acknowledged, some data not acknowledged
|
||||
fallthrough
|
||||
default:
|
||||
// panic("unknown i2c abortReason:" + strconv.Itoa(abortReason)
|
||||
err = makeI2CAbortError(abortReason)
|
||||
}
|
||||
}
|
||||
|
||||
// nostop means we are now at the end of a *message* but not the end of a *transfer*
|
||||
i2c.restartOnNext = nostop
|
||||
return err
|
||||
}
|
||||
|
||||
// rx is a primitive i2c blocking read routine. timeout is time to wait
|
||||
// in microseconds since calling this function for read to finish.
|
||||
func (i2c *I2C) rx(addr uint8, rx []byte, nostop bool, timeout uint64) (err error) {
|
||||
deadline := ticks() + timeout
|
||||
if addr >= 0x80 || isReservedI2CAddr(addr) {
|
||||
return ErrInvalidTgtAddr
|
||||
}
|
||||
rlen := len(rx)
|
||||
// Quick return if possible.
|
||||
if rlen == 0 {
|
||||
return nil
|
||||
}
|
||||
err = i2c.disable()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i2c.Bus.IC_TAR.Set(uint32(addr))
|
||||
i2c.enable()
|
||||
// If no timeout was passed timeoutCheck is false.
|
||||
abort := false
|
||||
var abortReason uint32
|
||||
byteCtr := 0
|
||||
for ; byteCtr < rlen; byteCtr++ {
|
||||
first := byteCtr == 0
|
||||
last := byteCtr == rlen-1
|
||||
for i2c.writeAvailable() == 0 {
|
||||
}
|
||||
i2c.Bus.IC_DATA_CMD.Set(
|
||||
boolToBit(first && i2c.restartOnNext)<<rp.I2C0_IC_DATA_CMD_RESTART_Pos |
|
||||
boolToBit(last && !nostop)<<rp.I2C0_IC_DATA_CMD_STOP_Pos |
|
||||
rp.I2C0_IC_DATA_CMD_CMD) // -> 1 for read
|
||||
|
||||
for !abort && i2c.readAvailable() == 0 {
|
||||
abortReason = i2c.getAbortReason()
|
||||
i2c.clearAbortReason()
|
||||
if abortReason != 0 {
|
||||
abort = true
|
||||
}
|
||||
if ticks() > deadline {
|
||||
i2c.restartOnNext = nostop
|
||||
return errI2CReadTimeout // If there was a timeout, don't attempt to do anything else.
|
||||
}
|
||||
}
|
||||
if abort {
|
||||
break
|
||||
}
|
||||
rx[byteCtr] = uint8(i2c.Bus.IC_DATA_CMD.Get())
|
||||
}
|
||||
|
||||
if abort {
|
||||
switch {
|
||||
case abortReason == 0 || abortReason&rp.I2C0_IC_TX_ABRT_SOURCE_ABRT_7B_ADDR_NOACK != 0:
|
||||
// No reported errors - seems to happen if there is nothing connected to the bus.
|
||||
// Address byte not acknowledged
|
||||
err = ErrI2CGeneric
|
||||
default:
|
||||
// undefined abort sequence
|
||||
err = makeI2CAbortError(abortReason)
|
||||
}
|
||||
}
|
||||
|
||||
i2c.restartOnNext = nostop
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -423,6 +368,7 @@ func (i2c *I2C) clearAbortReason() {
|
||||
i2c.Bus.IC_CLR_TX_ABRT.Get()
|
||||
}
|
||||
|
||||
// getAbortReason reads IC_TX_ABRT_SOURCE register.
|
||||
//go:inline
|
||||
func (i2c *I2C) getAbortReason() uint32 {
|
||||
return i2c.Bus.IC_TX_ABRT_SOURCE.Get()
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
//go:build !baremetal || (stm32 && !stm32f7x2 && !stm32l5x2) || fe310 || k210 || atmega
|
||||
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2 fe310 k210 atmega
|
||||
//go:build !baremetal || (stm32 && !stm32f7x2 && !stm32l5x2) || fe310 || k210 || (nxp && !mk66f18) || atmega
|
||||
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2 fe310 k210 nxp,!mk66f18 atmega
|
||||
|
||||
package machine
|
||||
|
||||
|
||||
@@ -18,6 +18,24 @@ var (
|
||||
ErrExist = errors.New("file exists")
|
||||
)
|
||||
|
||||
// The following code is copied from the official implementation.
|
||||
// src/internal/poll/fd.go
|
||||
|
||||
// ErrDeadlineExceeded is returned for an expired deadline.
|
||||
// This is exported by the os package as os.ErrDeadlineExceeded.
|
||||
var ErrDeadlineExceeded error = &DeadlineExceededError{}
|
||||
|
||||
// DeadlineExceededError is returned for an expired deadline.
|
||||
type DeadlineExceededError struct{}
|
||||
|
||||
// Implement the net.Error interface.
|
||||
// The string is "i/o timeout" because that is what was returned
|
||||
// by earlier Go versions. Changing it may break programs that
|
||||
// match on error strings.
|
||||
func (e *DeadlineExceededError) Error() string { return "i/o timeout" }
|
||||
func (e *DeadlineExceededError) Timeout() bool { return true }
|
||||
func (e *DeadlineExceededError) Temporary() bool { return true }
|
||||
|
||||
// The following code is copied from the official implementation.
|
||||
// https://github.com/golang/go/blob/4ce6a8e89668b87dce67e2f55802903d6eb9110a/src/os/error.go#L65-L104
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package os
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
|
||||
// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
@@ -31,9 +31,14 @@ func TestTempDir(t *testing.T) {
|
||||
|
||||
func TestChdir(t *testing.T) {
|
||||
// create and cd into a new directory
|
||||
oldDir, err := Getwd()
|
||||
if err != nil {
|
||||
t.Errorf("Getwd() returned %v", err)
|
||||
return
|
||||
}
|
||||
dir := "_os_test_TestChDir"
|
||||
Remove(dir)
|
||||
err := Mkdir(dir, 0755)
|
||||
err = Mkdir(dir, 0755)
|
||||
defer Remove(dir) // even though not quite sure which directory it will execute in
|
||||
if err != nil {
|
||||
t.Errorf("Mkdir(%s, 0755) returned %v", dir, err)
|
||||
@@ -55,7 +60,9 @@ func TestChdir(t *testing.T) {
|
||||
t.Errorf("Close %s: %s", file, err)
|
||||
}
|
||||
// cd back to original directory
|
||||
err = Chdir("..")
|
||||
// TODO: emulate "cd .." in wasi-libc better?
|
||||
//err = Chdir("..")
|
||||
err = Chdir(oldDir)
|
||||
if err != nil {
|
||||
t.Errorf("Chdir ..: %s", err)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
//go:build windows || darwin || (linux && !baremetal && !wasi)
|
||||
// +build windows darwin linux,!baremetal,!wasi
|
||||
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Test pipes on Unix and Windows systems.
|
||||
|
||||
package os_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestSmokePipe is a simple smoke test for Pipe().
|
||||
func TestSmokePipe(t *testing.T) {
|
||||
// Procedure:
|
||||
// 1. Get the bytes
|
||||
// 2. Light the bytes on fire
|
||||
// 3. Smoke the bytes
|
||||
|
||||
r, w, err := os.Pipe()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
return // TODO: remove once Fatal is fatal
|
||||
}
|
||||
defer r.Close()
|
||||
defer w.Close()
|
||||
|
||||
msg := []byte("Sed nvlla nisi ardva virtvs")
|
||||
n, err := w.Write(msg)
|
||||
if err != nil {
|
||||
t.Errorf("Writing to fresh pipe failed, error %v", err)
|
||||
}
|
||||
want := len(msg)
|
||||
if n != want {
|
||||
t.Errorf("Writing to fresh pipe wrote %d bytes, expected %d", n, want)
|
||||
}
|
||||
|
||||
buf := make([]byte, 2*len(msg))
|
||||
n, err = r.Read(buf)
|
||||
if err != nil {
|
||||
t.Errorf("Reading from pipe failed, error %v", err)
|
||||
}
|
||||
if n != want {
|
||||
t.Errorf("Reading from pipe got %d bytes, expected %d", n, want)
|
||||
}
|
||||
// Read() does not set len(buf), so do it here.
|
||||
buf = buf[:n]
|
||||
if !bytes.Equal(buf, msg) {
|
||||
t.Errorf("Reading from fresh pipe got wrong bytes")
|
||||
}
|
||||
}
|
||||
@@ -310,6 +310,13 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
|
||||
index = 0
|
||||
// Reset numFreeBlocks as allocations cannot wrap.
|
||||
numFreeBlocks = 0
|
||||
// In rare cases, the initial heap might be so small that there are
|
||||
// no blocks at all. In this case, it's better to jump back to the
|
||||
// start of the loop and try again, until the GC realizes there is
|
||||
// no memory and grows the heap.
|
||||
// This can sometimes happen on WebAssembly, where the initial heap
|
||||
// is created by whatever is left on the last memory page.
|
||||
continue
|
||||
}
|
||||
|
||||
// Is the block we're looking at free?
|
||||
|
||||
+153
-34
@@ -12,14 +12,23 @@ import (
|
||||
|
||||
// The underlying hashmap structure for Go.
|
||||
type hashmap struct {
|
||||
next *hashmap // hashmap after evacuate (for iterators)
|
||||
buckets unsafe.Pointer // pointer to array of buckets
|
||||
count uintptr
|
||||
keySize uint8 // maybe this can store the key type as well? E.g. keysize == 5 means string?
|
||||
valueSize uint8
|
||||
bucketBits uint8
|
||||
keyEqual func(x, y unsafe.Pointer, n uintptr) bool
|
||||
keyHash func(key unsafe.Pointer, size uintptr) uint32
|
||||
}
|
||||
|
||||
type hashmapAlgorithm uint8
|
||||
|
||||
const (
|
||||
hashmapAlgorithmBinary hashmapAlgorithm = iota
|
||||
hashmapAlgorithmString
|
||||
hashmapAlgorithmInterface
|
||||
)
|
||||
|
||||
// A hashmap bucket. A bucket is a container of 8 key/value pairs: first the
|
||||
// following two entries, then the 8 keys, then the 8 values. This somewhat odd
|
||||
// ordering is to make sure the keys and values are well aligned when one of
|
||||
@@ -32,9 +41,11 @@ type hashmapBucket struct {
|
||||
}
|
||||
|
||||
type hashmapIterator struct {
|
||||
bucketNumber uintptr
|
||||
bucket *hashmapBucket
|
||||
bucketIndex uint8
|
||||
buckets unsafe.Pointer // pointer to array of hashapBuckets
|
||||
numBuckets uintptr // length of buckets array
|
||||
bucketNumber uintptr // current index into buckets array
|
||||
bucket *hashmapBucket // current bucket in chain
|
||||
bucketIndex uint8 // current index into bucket
|
||||
}
|
||||
|
||||
// Get the topmost 8 bits of the hash, without using a special value (like 0).
|
||||
@@ -48,7 +59,7 @@ func hashmapTopHash(hash uint32) uint8 {
|
||||
}
|
||||
|
||||
// Create a new hashmap with the given keySize and valueSize.
|
||||
func hashmapMake(keySize, valueSize uint8, sizeHint uintptr) *hashmap {
|
||||
func hashmapMake(keySize, valueSize uint8, sizeHint uintptr, alg uint8) *hashmap {
|
||||
numBuckets := sizeHint / 8
|
||||
bucketBits := uint8(0)
|
||||
for numBuckets != 0 {
|
||||
@@ -57,14 +68,67 @@ func hashmapMake(keySize, valueSize uint8, sizeHint uintptr) *hashmap {
|
||||
}
|
||||
bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(keySize)*8 + uintptr(valueSize)*8
|
||||
buckets := alloc(bucketBufSize*(1<<bucketBits), nil)
|
||||
|
||||
keyHash := hashmapKeyHashAlg(hashmapAlgorithm(alg))
|
||||
keyEqual := hashmapKeyEqualAlg(hashmapAlgorithm(alg))
|
||||
|
||||
return &hashmap{
|
||||
buckets: buckets,
|
||||
keySize: keySize,
|
||||
valueSize: valueSize,
|
||||
bucketBits: bucketBits,
|
||||
keyEqual: keyEqual,
|
||||
keyHash: keyHash,
|
||||
}
|
||||
}
|
||||
|
||||
func hashmapKeyEqualAlg(alg hashmapAlgorithm) func(x, y unsafe.Pointer, n uintptr) bool {
|
||||
switch alg {
|
||||
case hashmapAlgorithmBinary:
|
||||
return memequal
|
||||
case hashmapAlgorithmString:
|
||||
return hashmapStringEqual
|
||||
case hashmapAlgorithmInterface:
|
||||
return hashmapInterfaceEqual
|
||||
default:
|
||||
// compiler bug :(
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func hashmapKeyHashAlg(alg hashmapAlgorithm) func(key unsafe.Pointer, n uintptr) uint32 {
|
||||
switch alg {
|
||||
case hashmapAlgorithmBinary:
|
||||
return hash32
|
||||
case hashmapAlgorithmString:
|
||||
return hashmapStringPtrHash
|
||||
case hashmapAlgorithmInterface:
|
||||
return hashmapInterfacePtrHash
|
||||
default:
|
||||
// compiler bug :(
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func hashmapShouldGrow(m *hashmap) bool {
|
||||
if m.bucketBits > uint8((unsafe.Sizeof(uintptr(0))*8)-3) {
|
||||
// Over this limit, we're likely to overflow uintptrs during calculations
|
||||
// or numbers of hash elements. Don't allow any more growth.
|
||||
// With 29 bits, this is 2^32 elements anyway.
|
||||
return false
|
||||
}
|
||||
|
||||
// "maximum" number of elements is 0.75 * buckets * elements per bucket
|
||||
// to avoid overflow, this is calculated as
|
||||
// max = 3 * (1/4 * buckets * elements per bucket)
|
||||
// = 3 * (buckets * (elements per bucket)/4)
|
||||
// = 3 * (buckets * (8/4)
|
||||
// = 3 * (buckets * 2)
|
||||
// = 6 * buckets
|
||||
max := (uintptr(6) << m.bucketBits)
|
||||
return m.count > max
|
||||
}
|
||||
|
||||
// Return the number of entries in this hashmap, called from the len builtin.
|
||||
// A nil hashmap is defined as having length 0.
|
||||
//go:inline
|
||||
@@ -83,13 +147,11 @@ func hashmapLenUnsafePointer(p unsafe.Pointer) int {
|
||||
|
||||
// Set a specified key to a given value. Grow the map if necessary.
|
||||
//go:nobounds
|
||||
func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) {
|
||||
func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint32) {
|
||||
tophash := hashmapTopHash(hash)
|
||||
|
||||
if m.buckets == nil {
|
||||
// No bucket was allocated yet, do so now.
|
||||
m.buckets = unsafe.Pointer(hashmapInsertIntoNewBucket(m, key, value, tophash))
|
||||
return
|
||||
if hashmapShouldGrow(m) {
|
||||
hashmapGrow(m)
|
||||
}
|
||||
|
||||
numBuckets := uintptr(1) << m.bucketBits
|
||||
@@ -118,7 +180,7 @@ func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint3
|
||||
}
|
||||
if bucket.tophash[i] == tophash {
|
||||
// Could be an existing key that's the same.
|
||||
if keyEqual(key, slotKey, uintptr(m.keySize)) {
|
||||
if m.keyEqual(key, slotKey, uintptr(m.keySize)) {
|
||||
// found same key, replace it
|
||||
memcpy(slotValue, value, uintptr(m.valueSize))
|
||||
return
|
||||
@@ -158,9 +220,35 @@ func hashmapInsertIntoNewBucket(m *hashmap, key, value unsafe.Pointer, tophash u
|
||||
return bucket
|
||||
}
|
||||
|
||||
func hashmapGrow(m *hashmap) {
|
||||
|
||||
// clone map as empty
|
||||
n := *m
|
||||
n.count = 0
|
||||
|
||||
// allocate our new buckets twice as big
|
||||
n.bucketBits = m.bucketBits + 1
|
||||
numBuckets := uintptr(1) << n.bucketBits
|
||||
bucketBufSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8
|
||||
n.buckets = alloc(bucketBufSize*numBuckets, nil)
|
||||
|
||||
// use a hashmap iterator to go through the old map
|
||||
var it hashmapIterator
|
||||
|
||||
var key = alloc(uintptr(m.keySize), nil)
|
||||
var value = alloc(uintptr(m.valueSize), nil)
|
||||
|
||||
for hashmapNext(m, &it, key, value) {
|
||||
h := m.keyHash(key, uintptr(m.keySize))
|
||||
hashmapSet(&n, key, value, h)
|
||||
}
|
||||
|
||||
*m = n
|
||||
}
|
||||
|
||||
// Get the value of a specified key, or zero the value if not found.
|
||||
//go:nobounds
|
||||
func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) bool {
|
||||
func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash uint32) bool {
|
||||
if m == nil {
|
||||
// Getting a value out of a nil map is valid. From the spec:
|
||||
// > if the map is nil or does not contain such an entry, a[x] is the
|
||||
@@ -189,7 +277,7 @@ func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash u
|
||||
slotValue := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotValueOffset)
|
||||
if bucket.tophash[i] == tophash {
|
||||
// This could be the key we're looking for.
|
||||
if keyEqual(key, slotKey, uintptr(m.keySize)) {
|
||||
if m.keyEqual(key, slotKey, uintptr(m.keySize)) {
|
||||
// Found the key, copy it.
|
||||
memcpy(value, slotValue, uintptr(m.valueSize))
|
||||
return true
|
||||
@@ -207,7 +295,7 @@ func hashmapGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr, hash u
|
||||
// Delete a given key from the map. No-op when the key does not exist in the
|
||||
// map.
|
||||
//go:nobounds
|
||||
func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) {
|
||||
func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32) {
|
||||
if m == nil {
|
||||
// The delete builtin is defined even when the map is nil. From the spec:
|
||||
// > If the map m is nil or the element m[k] does not exist, delete is a
|
||||
@@ -233,7 +321,7 @@ func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32, keyEqual func(x,
|
||||
slotKey := unsafe.Pointer(uintptr(unsafe.Pointer(bucket)) + slotKeyOffset)
|
||||
if bucket.tophash[i] == tophash {
|
||||
// This could be the key we're looking for.
|
||||
if keyEqual(key, slotKey, uintptr(m.keySize)) {
|
||||
if m.keyEqual(key, slotKey, uintptr(m.keySize)) {
|
||||
// Found the key, delete it.
|
||||
bucket.tophash[i] = 0
|
||||
m.count--
|
||||
@@ -249,13 +337,16 @@ func hashmapDelete(m *hashmap, key unsafe.Pointer, hash uint32, keyEqual func(x,
|
||||
//go:nobounds
|
||||
func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) bool {
|
||||
if m == nil {
|
||||
// Iterating over a nil slice appears to be allowed by the Go spec:
|
||||
// https://groups.google.com/g/golang-nuts/c/gVgVLQU1FFE?pli=1
|
||||
// https://play.golang.org/p/S8jxAMytKDB
|
||||
// From the spec: If the map is nil, the number of iterations is 0.
|
||||
return false
|
||||
}
|
||||
|
||||
numBuckets := uintptr(1) << m.bucketBits
|
||||
if it.buckets == nil {
|
||||
// initialize iterator
|
||||
it.buckets = m.buckets
|
||||
it.numBuckets = uintptr(1) << m.bucketBits
|
||||
}
|
||||
|
||||
for {
|
||||
if it.bucketIndex >= 8 {
|
||||
// end of bucket, move to the next in the chain
|
||||
@@ -263,12 +354,12 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
|
||||
it.bucket = it.bucket.next
|
||||
}
|
||||
if it.bucket == nil {
|
||||
if it.bucketNumber >= numBuckets {
|
||||
if it.bucketNumber >= it.numBuckets {
|
||||
// went through all buckets
|
||||
return false
|
||||
}
|
||||
bucketSize := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*8
|
||||
bucketAddr := uintptr(m.buckets) + bucketSize*it.bucketNumber
|
||||
bucketAddr := uintptr(it.buckets) + bucketSize*it.bucketNumber
|
||||
it.bucket = (*hashmapBucket)(unsafe.Pointer(bucketAddr))
|
||||
it.bucketNumber++ // next bucket
|
||||
}
|
||||
@@ -281,11 +372,29 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
|
||||
bucketAddr := uintptr(unsafe.Pointer(it.bucket))
|
||||
slotKeyOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*uintptr(it.bucketIndex)
|
||||
slotKey := unsafe.Pointer(bucketAddr + slotKeyOffset)
|
||||
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*uintptr(it.bucketIndex)
|
||||
slotValue := unsafe.Pointer(bucketAddr + slotValueOffset)
|
||||
memcpy(key, slotKey, uintptr(m.keySize))
|
||||
memcpy(value, slotValue, uintptr(m.valueSize))
|
||||
it.bucketIndex++
|
||||
|
||||
if it.buckets == m.buckets {
|
||||
// Our view of the buckets is the same as the parent map.
|
||||
// Just copy the value we have
|
||||
slotValueOffset := unsafe.Sizeof(hashmapBucket{}) + uintptr(m.keySize)*8 + uintptr(m.valueSize)*uintptr(it.bucketIndex)
|
||||
slotValue := unsafe.Pointer(bucketAddr + slotValueOffset)
|
||||
memcpy(value, slotValue, uintptr(m.valueSize))
|
||||
it.bucketIndex++
|
||||
} else {
|
||||
it.bucketIndex++
|
||||
|
||||
// Our view of the buckets doesn't match the parent map.
|
||||
// Look up the key in the new buckets and return that value if it exists
|
||||
hash := m.keyHash(key, uintptr(m.keySize))
|
||||
ok := hashmapGet(m, key, value, uintptr(m.valueSize), hash)
|
||||
if !ok {
|
||||
// doesn't exist in parent map; try next key
|
||||
continue
|
||||
}
|
||||
|
||||
// All good.
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -296,7 +405,7 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
|
||||
func hashmapBinarySet(m *hashmap, key, value unsafe.Pointer) {
|
||||
// TODO: detect nil map here and throw a better panic message?
|
||||
hash := hash32(key, uintptr(m.keySize))
|
||||
hashmapSet(m, key, value, hash, memequal)
|
||||
hashmapSet(m, key, value, hash)
|
||||
}
|
||||
|
||||
func hashmapBinaryGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr) bool {
|
||||
@@ -305,7 +414,7 @@ func hashmapBinaryGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr)
|
||||
return false
|
||||
}
|
||||
hash := hash32(key, uintptr(m.keySize))
|
||||
return hashmapGet(m, key, value, valueSize, hash, memequal)
|
||||
return hashmapGet(m, key, value, valueSize, hash)
|
||||
}
|
||||
|
||||
func hashmapBinaryDelete(m *hashmap, key unsafe.Pointer) {
|
||||
@@ -313,7 +422,7 @@ func hashmapBinaryDelete(m *hashmap, key unsafe.Pointer) {
|
||||
return
|
||||
}
|
||||
hash := hash32(key, uintptr(m.keySize))
|
||||
hashmapDelete(m, key, hash, memequal)
|
||||
hashmapDelete(m, key, hash)
|
||||
}
|
||||
|
||||
// Hashmap with string keys (a common case).
|
||||
@@ -327,19 +436,24 @@ func hashmapStringHash(s string) uint32 {
|
||||
return hash32(unsafe.Pointer(_s.ptr), uintptr(_s.length))
|
||||
}
|
||||
|
||||
func hashmapStringPtrHash(sptr unsafe.Pointer, size uintptr) uint32 {
|
||||
_s := *(*_string)(sptr)
|
||||
return hash32(unsafe.Pointer(_s.ptr), uintptr(_s.length))
|
||||
}
|
||||
|
||||
func hashmapStringSet(m *hashmap, key string, value unsafe.Pointer) {
|
||||
hash := hashmapStringHash(key)
|
||||
hashmapSet(m, unsafe.Pointer(&key), value, hash, hashmapStringEqual)
|
||||
hashmapSet(m, unsafe.Pointer(&key), value, hash)
|
||||
}
|
||||
|
||||
func hashmapStringGet(m *hashmap, key string, value unsafe.Pointer, valueSize uintptr) bool {
|
||||
hash := hashmapStringHash(key)
|
||||
return hashmapGet(m, unsafe.Pointer(&key), value, valueSize, hash, hashmapStringEqual)
|
||||
return hashmapGet(m, unsafe.Pointer(&key), value, valueSize, hash)
|
||||
}
|
||||
|
||||
func hashmapStringDelete(m *hashmap, key string) {
|
||||
hash := hashmapStringHash(key)
|
||||
hashmapDelete(m, unsafe.Pointer(&key), hash, hashmapStringEqual)
|
||||
hashmapDelete(m, unsafe.Pointer(&key), hash)
|
||||
}
|
||||
|
||||
// Hashmap with interface keys (for everything else).
|
||||
@@ -427,21 +541,26 @@ func hashmapInterfaceHash(itf interface{}) uint32 {
|
||||
}
|
||||
}
|
||||
|
||||
func hashmapInterfacePtrHash(iptr unsafe.Pointer, size uintptr) uint32 {
|
||||
_i := *(*_interface)(iptr)
|
||||
return hashmapInterfaceHash(_i)
|
||||
}
|
||||
|
||||
func hashmapInterfaceEqual(x, y unsafe.Pointer, n uintptr) bool {
|
||||
return *(*interface{})(x) == *(*interface{})(y)
|
||||
}
|
||||
|
||||
func hashmapInterfaceSet(m *hashmap, key interface{}, value unsafe.Pointer) {
|
||||
hash := hashmapInterfaceHash(key)
|
||||
hashmapSet(m, unsafe.Pointer(&key), value, hash, hashmapInterfaceEqual)
|
||||
hashmapSet(m, unsafe.Pointer(&key), value, hash)
|
||||
}
|
||||
|
||||
func hashmapInterfaceGet(m *hashmap, key interface{}, value unsafe.Pointer, valueSize uintptr) bool {
|
||||
hash := hashmapInterfaceHash(key)
|
||||
return hashmapGet(m, unsafe.Pointer(&key), value, valueSize, hash, hashmapInterfaceEqual)
|
||||
return hashmapGet(m, unsafe.Pointer(&key), value, valueSize, hash)
|
||||
}
|
||||
|
||||
func hashmapInterfaceDelete(m *hashmap, key interface{}) {
|
||||
hash := hashmapInterfaceHash(key)
|
||||
hashmapDelete(m, unsafe.Pointer(&key), hash, hashmapInterfaceEqual)
|
||||
hashmapDelete(m, unsafe.Pointer(&key), hash)
|
||||
}
|
||||
|
||||
@@ -74,3 +74,14 @@ func nanotime() int64 {
|
||||
func os_sigpipe() {
|
||||
runtimePanic("too many writes on closed pipe")
|
||||
}
|
||||
|
||||
// LockOSThread wires the calling goroutine to its current operating system thread.
|
||||
// Stub for now
|
||||
// Called by go1.18 standard library on windows, see https://github.com/golang/go/issues/49320
|
||||
func LockOSThread() {
|
||||
}
|
||||
|
||||
// UnlockOSThread undoes an earlier call to LockOSThread.
|
||||
// Stub for now
|
||||
func UnlockOSThread() {
|
||||
}
|
||||
|
||||
@@ -153,9 +153,18 @@ func Kill(pid int, sig Signal) (err error) {
|
||||
|
||||
type SysProcAttr struct{}
|
||||
|
||||
func Pipe2(p []int, flags int) (err error) {
|
||||
return ENOSYS // TODO
|
||||
}
|
||||
// TODO
|
||||
type WaitStatus uint32
|
||||
|
||||
func (w WaitStatus) Exited() bool { return false }
|
||||
func (w WaitStatus) ExitStatus() int { return 0 }
|
||||
func (w WaitStatus) Signaled() bool { return false }
|
||||
func (w WaitStatus) Signal() Signal { return 0 }
|
||||
func (w WaitStatus) CoreDump() bool { return false }
|
||||
func (w WaitStatus) Stopped() bool { return false }
|
||||
func (w WaitStatus) Continued() bool { return false }
|
||||
func (w WaitStatus) StopSignal() Signal { return 0 }
|
||||
func (w WaitStatus) TrapCause() int { return 0 }
|
||||
|
||||
func Getenv(key string) (value string, found bool) {
|
||||
data := cstring(key)
|
||||
|
||||
@@ -74,13 +74,20 @@ const (
|
||||
|
||||
type Signal int
|
||||
|
||||
// Source: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/sys/signal.h
|
||||
const (
|
||||
SIGCHLD Signal = 0x14
|
||||
SIGINT Signal = 0x2
|
||||
SIGKILL Signal = 0x9
|
||||
SIGTRAP Signal = 0x5
|
||||
SIGQUIT Signal = 0x3
|
||||
SIGTERM Signal = 0xf
|
||||
SIGINT Signal = 2 /* interrupt */
|
||||
SIGQUIT Signal = 3 /* quit */
|
||||
SIGILL Signal = 4 /* illegal instruction (not reset when caught) */
|
||||
SIGTRAP Signal = 5 /* trace trap (not reset when caught) */
|
||||
SIGABRT Signal = 6 /* abort() */
|
||||
SIGFPE Signal = 8 /* floating point exception */
|
||||
SIGKILL Signal = 9 /* kill (cannot be caught or ignored) */
|
||||
SIGBUS Signal = 10 /* bus error */
|
||||
SIGSEGV Signal = 11 /* segmentation violation */
|
||||
SIGPIPE Signal = 13 /* write on a pipe with no one to read it */
|
||||
SIGTERM Signal = 15 /* software termination signal from kill */
|
||||
SIGCHLD Signal = 20 /* to parent on child stop or exit */
|
||||
)
|
||||
|
||||
func (s Signal) Signal() {}
|
||||
@@ -239,6 +246,19 @@ func Fdopendir(fd int) (dir uintptr, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func Pipe2(fds []int, flags int) (err error) {
|
||||
// Mac only has Pipe, which ignores the flags argument
|
||||
buf := make([]int32, 2)
|
||||
fail := int(libc_pipe(&buf[0]))
|
||||
if fail < 0 {
|
||||
err = getErrno()
|
||||
} else {
|
||||
fds[0] = int(buf[0])
|
||||
fds[1] = int(buf[1])
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func readdir_r(dir uintptr, entry *Dirent, result **Dirent) (err error) {
|
||||
e1 := libc_readdir_r(unsafe.Pointer(dir), unsafe.Pointer(entry), unsafe.Pointer(result))
|
||||
if e1 != 0 {
|
||||
@@ -271,3 +291,7 @@ func libc_fstat(fd int32, ptr unsafe.Pointer) int32
|
||||
// int lstat(const char *path, struct stat * buf);
|
||||
//export lstat$INODE64
|
||||
func libc_lstat(pathname *byte, ptr unsafe.Pointer) int32
|
||||
|
||||
// int pipe(int32 *fds);
|
||||
//export pipe
|
||||
func libc_pipe(fds *int32) int32
|
||||
|
||||
@@ -63,3 +63,7 @@ var libcErrno uintptr
|
||||
func getErrno() error {
|
||||
return Errno(libcErrno)
|
||||
}
|
||||
|
||||
func Pipe2(p []int, flags int) (err error) {
|
||||
return ENOSYS // TODO
|
||||
}
|
||||
|
||||
@@ -9,16 +9,24 @@ import (
|
||||
)
|
||||
|
||||
// https://github.com/WebAssembly/wasi-libc/blob/main/expected/wasm32-wasi/predefined-macros.txt
|
||||
// disagrees with ../../lib/wasi-libc/libc-top-half/musl/arch/wasm32/bits/signal.h for SIGCHLD?
|
||||
// https://github.com/WebAssembly/wasi-libc/issues/271
|
||||
|
||||
type Signal int
|
||||
|
||||
const (
|
||||
SIGCHLD Signal = 16
|
||||
SIGINT Signal = 2
|
||||
SIGKILL Signal = 9
|
||||
SIGTRAP Signal = 5
|
||||
SIGQUIT Signal = 3
|
||||
SIGILL Signal = 4
|
||||
SIGTRAP Signal = 5
|
||||
SIGABRT Signal = 6
|
||||
SIGBUS Signal = 7
|
||||
SIGFPE Signal = 8
|
||||
SIGKILL Signal = 9
|
||||
SIGSEGV Signal = 11
|
||||
SIGPIPE Signal = 13
|
||||
SIGTERM Signal = 15
|
||||
SIGCHLD Signal = 17
|
||||
)
|
||||
|
||||
func (s Signal) Signal() {}
|
||||
@@ -284,6 +292,10 @@ func Lstat(path string, p *Stat_t) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func Pipe2(p []int, flags int) (err error) {
|
||||
return ENOSYS // TODO
|
||||
}
|
||||
|
||||
// int stat(const char *path, struct stat * buf);
|
||||
//export stat
|
||||
func libc_stat(pathname *byte, ptr unsafe.Pointer) int32
|
||||
|
||||
@@ -180,6 +180,9 @@ type SysProcAttr struct {
|
||||
func Getgroups() ([]int, error) { return []int{1}, nil }
|
||||
func Gettimeofday(tv *Timeval) error { return ENOSYS }
|
||||
func Kill(pid int, signum Signal) error { return ENOSYS }
|
||||
func Pipe2(p []int, flags int) (err error) {
|
||||
return ENOSYS // TODO
|
||||
}
|
||||
func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
||||
return 0, ENOSYS
|
||||
}
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
package testing
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// InternalFuzzTarget is an internal type but exported because it is
|
||||
// cross-package; it is part of the implementation of the "go test" command.
|
||||
type InternalFuzzTarget struct {
|
||||
Name string
|
||||
Fn func(f *F)
|
||||
}
|
||||
|
||||
// F is a type passed to fuzz tests.
|
||||
//
|
||||
// Fuzz tests run generated inputs against a provided fuzz target, which can
|
||||
// find and report potential bugs in the code being tested.
|
||||
//
|
||||
// A fuzz test runs the seed corpus by default, which includes entries provided
|
||||
// by (*F).Add and entries in the testdata/fuzz/<FuzzTestName> directory. After
|
||||
// any necessary setup and calls to (*F).Add, the fuzz test must then call
|
||||
// (*F).Fuzz to provide the fuzz target. See the testing package documentation
|
||||
// for an example, and see the F.Fuzz and F.Add method documentation for
|
||||
// details.
|
||||
//
|
||||
// *F methods can only be called before (*F).Fuzz. Once the test is
|
||||
// executing the fuzz target, only (*T) methods can be used. The only *F methods
|
||||
// that are allowed in the (*F).Fuzz function are (*F).Failed and (*F).Name.
|
||||
type F struct {
|
||||
common
|
||||
fuzzContext *fuzzContext
|
||||
testContext *testContext
|
||||
|
||||
// inFuzzFn is true when the fuzz function is running. Most F methods cannot
|
||||
// be called when inFuzzFn is true.
|
||||
inFuzzFn bool
|
||||
|
||||
// corpus is a set of seed corpus entries, added with F.Add and loaded
|
||||
// from testdata.
|
||||
corpus []corpusEntry
|
||||
|
||||
result fuzzResult
|
||||
fuzzCalled bool
|
||||
}
|
||||
|
||||
// corpusEntry is an alias to the same type as internal/fuzz.CorpusEntry.
|
||||
// We use a type alias because we don't want to export this type, and we can't
|
||||
// import internal/fuzz from testing.
|
||||
type corpusEntry = struct {
|
||||
Parent string
|
||||
Path string
|
||||
Data []byte
|
||||
Values []interface{}
|
||||
Generation int
|
||||
IsSeed bool
|
||||
}
|
||||
|
||||
// Add will add the arguments to the seed corpus for the fuzz test. This will be
|
||||
// a no-op if called after or within the fuzz target, and args must match the
|
||||
// arguments for the fuzz target.
|
||||
func (f *F) Add(args ...interface{}) {
|
||||
var values []interface{}
|
||||
for i := range args {
|
||||
if t := reflect.TypeOf(args[i]); !supportedTypes[t] {
|
||||
panic(fmt.Sprintf("testing: unsupported type to Add %v", t))
|
||||
}
|
||||
values = append(values, args[i])
|
||||
}
|
||||
f.corpus = append(f.corpus, corpusEntry{Values: values, IsSeed: true, Path: fmt.Sprintf("seed#%d", len(f.corpus))})
|
||||
}
|
||||
|
||||
// supportedTypes represents all of the supported types which can be fuzzed.
|
||||
var supportedTypes = map[reflect.Type]bool{
|
||||
reflect.TypeOf(([]byte)("")): true,
|
||||
reflect.TypeOf((string)("")): true,
|
||||
reflect.TypeOf((bool)(false)): true,
|
||||
reflect.TypeOf((byte)(0)): true,
|
||||
reflect.TypeOf((rune)(0)): true,
|
||||
reflect.TypeOf((float32)(0)): true,
|
||||
reflect.TypeOf((float64)(0)): true,
|
||||
reflect.TypeOf((int)(0)): true,
|
||||
reflect.TypeOf((int8)(0)): true,
|
||||
reflect.TypeOf((int16)(0)): true,
|
||||
reflect.TypeOf((int32)(0)): true,
|
||||
reflect.TypeOf((int64)(0)): true,
|
||||
reflect.TypeOf((uint)(0)): true,
|
||||
reflect.TypeOf((uint8)(0)): true,
|
||||
reflect.TypeOf((uint16)(0)): true,
|
||||
reflect.TypeOf((uint32)(0)): true,
|
||||
reflect.TypeOf((uint64)(0)): true,
|
||||
}
|
||||
|
||||
// Fuzz runs the fuzz function, ff, for fuzz testing. If ff fails for a set of
|
||||
// arguments, those arguments will be added to the seed corpus.
|
||||
//
|
||||
// ff must be a function with no return value whose first argument is *T and
|
||||
// whose remaining arguments are the types to be fuzzed.
|
||||
// For example:
|
||||
//
|
||||
// f.Fuzz(func(t *testing.T, b []byte, i int) { ... })
|
||||
//
|
||||
// The following types are allowed: []byte, string, bool, byte, rune, float32,
|
||||
// float64, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64.
|
||||
// More types may be supported in the future.
|
||||
//
|
||||
// ff must not call any *F methods, e.g. (*F).Log, (*F).Error, (*F).Skip. Use
|
||||
// the corresponding *T method instead. The only *F methods that are allowed in
|
||||
// the (*F).Fuzz function are (*F).Failed and (*F).Name.
|
||||
//
|
||||
// This function should be fast and deterministic, and its behavior should not
|
||||
// depend on shared state. No mutatable input arguments, or pointers to them,
|
||||
// should be retained between executions of the fuzz function, as the memory
|
||||
// backing them may be mutated during a subsequent invocation. ff must not
|
||||
// modify the underlying data of the arguments provided by the fuzzing engine.
|
||||
//
|
||||
// When fuzzing, F.Fuzz does not return until a problem is found, time runs out
|
||||
// (set with -fuzztime), or the test process is interrupted by a signal. F.Fuzz
|
||||
// should be called exactly once, unless F.Skip or F.Fail is called beforehand.
|
||||
func (f *F) Fuzz(ff interface{}) {
|
||||
f.failed = true
|
||||
f.result.N = 0
|
||||
f.result.T = 0
|
||||
f.result.Error = errors.New("operation not implemented")
|
||||
return
|
||||
}
|
||||
|
||||
// fuzzContext holds fields common to all fuzz tests.
|
||||
type fuzzContext struct {
|
||||
deps testDeps
|
||||
mode fuzzMode
|
||||
}
|
||||
|
||||
type fuzzMode uint8
|
||||
|
||||
// fuzzResult contains the results of a fuzz run.
|
||||
type fuzzResult struct {
|
||||
N int // The number of iterations.
|
||||
T time.Duration // The total time taken.
|
||||
Error error // Error is the error from the failing input
|
||||
}
|
||||
@@ -430,15 +430,6 @@ type testDeps interface {
|
||||
MatchString(pat, str string) (bool, error)
|
||||
}
|
||||
|
||||
func MainStart(deps interface{}, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
|
||||
Init()
|
||||
return &M{
|
||||
Tests: tests,
|
||||
Benchmarks: benchmarks,
|
||||
deps: deps.(testDeps),
|
||||
}
|
||||
}
|
||||
|
||||
// Run runs the tests. It returns an exit code to pass to os.Exit.
|
||||
func (m *M) Run() (code int) {
|
||||
defer func() {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
//go:build go1.18
|
||||
// +build go1.18
|
||||
|
||||
package testing
|
||||
|
||||
// MainStart is meant for use by tests generated by 'go test'.
|
||||
// It is not meant to be called directly and is not subject to the Go 1 compatibility document.
|
||||
// It may change signature from release to release.
|
||||
func MainStart(deps interface{}, tests []InternalTest, benchmarks []InternalBenchmark, fuzzTargets []InternalFuzzTarget, examples []InternalExample) *M {
|
||||
Init()
|
||||
return &M{
|
||||
Tests: tests,
|
||||
Benchmarks: benchmarks,
|
||||
deps: deps.(testDeps),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//go:build !go1.18
|
||||
// +build !go1.18
|
||||
|
||||
package testing
|
||||
|
||||
// MainStart is meant for use by tests generated by 'go test'.
|
||||
// It is not meant to be called directly and is not subject to the Go 1 compatibility document.
|
||||
// It may change signature from release to release.
|
||||
func MainStart(deps interface{}, tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) *M {
|
||||
Init()
|
||||
return &M{
|
||||
Tests: tests,
|
||||
Benchmarks: benchmarks,
|
||||
deps: deps.(testDeps),
|
||||
}
|
||||
}
|
||||
@@ -6,5 +6,5 @@
|
||||
"-Wl,--defsym=_stack_size=512"
|
||||
],
|
||||
"flash-command": "avrdude -c arduino -p atmega328p -b 57600 -P {port} -U flash:w:{hex}:i",
|
||||
"emulator": ["simavr", "-m", "atmega328p", "-f", "16000000"]
|
||||
"emulator": "simavr -m atmega328p -f 16000000 {}"
|
||||
}
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
],
|
||||
"flash-command": "avrdude -c arduino -p atmega328p -P {port} -U flash:w:{hex}:i",
|
||||
"serial-port": ["acm:2341:0043", "acm:2341:0001", "acm:2a03:0043", "acm:2341:0243"],
|
||||
"emulator": ["simavr", "-m", "atmega328p", "-f", "16000000"]
|
||||
"emulator": "simavr -m atmega328p -f 16000000 {}"
|
||||
}
|
||||
|
||||
@@ -13,5 +13,5 @@
|
||||
"targets/avr.S",
|
||||
"src/device/avr/atmega1284p.s"
|
||||
],
|
||||
"emulator": ["simavr", "-m", "atmega1284p", "-f", "20000000"]
|
||||
"emulator": "simavr -m atmega1284p -f 20000000 {}"
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@
|
||||
"extra-files": [
|
||||
"targets/cortex-m-qemu.s"
|
||||
],
|
||||
"emulator": ["qemu-system-arm", "-machine", "lm3s6965evb", "-semihosting", "-nographic", "-kernel"]
|
||||
"emulator": "qemu-system-arm -machine lm3s6965evb -semihosting -nographic -kernel {}"
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
"-fshort-enums",
|
||||
"-fomit-frame-pointer",
|
||||
"-mfloat-abi=soft",
|
||||
"-fno-exceptions", "-fno-unwind-tables",
|
||||
"-fno-exceptions", "-fno-unwind-tables", "-fno-asynchronous-unwind-tables",
|
||||
"-ffunction-sections", "-fdata-sections"
|
||||
],
|
||||
"ldflags": [
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
"inherits": ["cortex-m"],
|
||||
"llvm-target": "thumbv6m-unknown-unknown-eabi",
|
||||
"cpu": "cortex-m0",
|
||||
"features": "+armv6-m,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
"features": "+armv6-m,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
"inherits": ["cortex-m"],
|
||||
"llvm-target": "thumbv6m-unknown-unknown-eabi",
|
||||
"cpu": "cortex-m0plus",
|
||||
"features": "+armv6-m,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
"features": "+armv6-m,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
"inherits": ["cortex-m"],
|
||||
"llvm-target": "thumbv7m-unknown-unknown-eabi",
|
||||
"cpu": "cortex-m3",
|
||||
"features": "+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
"features": "+armv7-m,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-dsp,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
"inherits": ["cortex-m"],
|
||||
"llvm-target": "thumbv7em-unknown-unknown-eabi",
|
||||
"cpu": "cortex-m4",
|
||||
"features": "+armv7e-m,+dsp,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
"features": "+armv7e-m,+dsp,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
"inherits": ["cortex-m"],
|
||||
"llvm-target": "thumbv7em-unknown-unknown-eabi",
|
||||
"cpu": "cortex-m7",
|
||||
"features": "+armv7e-m,+dsp,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
"features": "+armv7e-m,+dsp,+hwdiv,+soft-float,+strict-align,+thumb-mode,-aes,-bf16,-cdecp0,-cdecp1,-cdecp2,-cdecp3,-cdecp4,-cdecp5,-cdecp6,-cdecp7,-crc,-crypto,-d32,-dotprod,-fp-armv8,-fp-armv8d16,-fp-armv8d16sp,-fp-armv8sp,-fp16,-fp16fml,-fp64,-fpregs,-fullfp16,-hwdiv-arm,-i8mm,-lob,-mve,-mve.fp,-neon,-pacbti,-ras,-sb,-sha2,-vfp2,-vfp2sp,-vfp3,-vfp3d16,-vfp3d16sp,-vfp3sp,-vfp4,-vfp4d16,-vfp4d16sp,-vfp4sp"
|
||||
}
|
||||
|
||||
@@ -6,5 +6,5 @@
|
||||
"-Wl,--defsym=_stack_size=128"
|
||||
],
|
||||
"flash-command": "micronucleus --run {hex}",
|
||||
"emulator": ["simavr", "-m", "attiny85", "-f", "16000000"]
|
||||
"emulator": "simavr -m attiny85 -f 16000000 {}"
|
||||
}
|
||||
|
||||
+4
-1
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"inherits": ["xtensa"],
|
||||
"cpu": "esp32",
|
||||
"features": "+atomctl,+bool,+coprocessor,+debug,+density,+dfpaccel,+div32,+exception,+fp,+highpriinterrupts,+interrupt,+loop,+mac16,+memctl,+miscsr,+mul32,+mul32high,+nsa,+prid,+regprotect,+rvector,+s32c1i,+sext,+threadptr,+timerint,+windowed",
|
||||
"build-tags": ["esp32", "esp"],
|
||||
"scheduler": "tasks",
|
||||
"serial": "uart",
|
||||
@@ -14,5 +15,7 @@
|
||||
"src/internal/task/task_stack_esp32.S"
|
||||
],
|
||||
"binary-format": "esp32",
|
||||
"flash-command": "esptool.py --chip=esp32 --port {port} write_flash 0x1000 {bin} -ff 80m -fm dout"
|
||||
"flash-command": "esptool.py --chip=esp32 --port {port} write_flash 0x1000 {bin} -ff 80m -fm dout",
|
||||
"emulator": "qemu-system-xtensa -machine esp32 -nographic -drive file={img},if=mtd,format=raw",
|
||||
"gdb": ["xtensa-esp32-elf-gdb"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"inherits": ["riscv32"],
|
||||
"features": "+c,+m,-relax,-save-restore",
|
||||
"features": "+c,+m",
|
||||
"build-tags": ["esp32c3", "esp"],
|
||||
"serial": "uart",
|
||||
"rtlib": "compiler-rt",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"inherits": ["xtensa"],
|
||||
"cpu": "esp8266",
|
||||
"features": "+debug,+density,+exception,+extendedl32r,+highpriinterrupts,+interrupt,+mul32,+nsa,+prid,+regprotect,+rvector,+timerint",
|
||||
"build-tags": ["esp8266", "esp"],
|
||||
"scheduler": "tasks",
|
||||
"linker": "xtensa-esp32-elf-ld",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"inherits": ["riscv32"],
|
||||
"cpu": "sifive-e31",
|
||||
"features": "+a,+c,+m,-64bit,-relax,-save-restore",
|
||||
"features": "+a,+c,+m",
|
||||
"build-tags": ["fe310", "sifive"]
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user