mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-02 18:17:46 +00:00
Compare commits
57 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b9ce6c3374 | |||
| cab3834bc9 | |||
| 7f970a45c2 | |||
| ebf70ab18e | |||
| 226744a538 | |||
| dc876c6ed4 | |||
| 5a09084c73 | |||
| 6c9074772c | |||
| e49663809b | |||
| 7d6d93f7aa | |||
| 8c54e3dd88 | |||
| 47c0debe4b | |||
| 9a1cde40a8 | |||
| 20fc814635 | |||
| 64d8a04308 | |||
| b95effbdd7 | |||
| 92c130c7be | |||
| 31c4bc1151 | |||
| 42f5e55ed5 | |||
| 81da7bb4c1 | |||
| 209754493b | |||
| b0aef96340 | |||
| 056394e24b | |||
| 1545659817 | |||
| 38e3d55e64 | |||
| 66da29e89f | |||
| c180d6fe2f | |||
| cdea833b5c | |||
| c2eaa495df | |||
| 3476100dd0 | |||
| 07c7eff3c3 | |||
| a1be8cd9fe | |||
| 52b9fcd57f | |||
| ea53ace270 | |||
| a6cd072fa1 | |||
| 4372dbdd41 | |||
| 17bb1fec44 | |||
| f4fd79f7be | |||
| 811b13a9d3 | |||
| 6e97079367 | |||
| 9c7bbce029 | |||
| 0ec1cb1e19 | |||
| e7118e5bda | |||
| 150d9d1c6b | |||
| 8fe039156b | |||
| 2d17dec7bf | |||
| c1b267a208 | |||
| f02c56c9e0 | |||
| c5879c682c | |||
| 190c20825f | |||
| d04eea7185 | |||
| f24cd31895 | |||
| 2044f6fbcc | |||
| d55a89f96a | |||
| 080a6648e9 | |||
| ec0a142190 | |||
| b7fcf6ad68 |
@@ -109,9 +109,9 @@ jobs:
|
||||
# "make lint" fails before go 1.21 because internal/tools/go.mod specifies packages that require go 1.21
|
||||
fmt-check: false
|
||||
resource_class: large
|
||||
test-llvm19-go123:
|
||||
test-llvm19-go124:
|
||||
docker:
|
||||
- image: golang:1.23-bullseye
|
||||
- image: golang:1.24-bullseye
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "19"
|
||||
@@ -124,4 +124,4 @@ workflows:
|
||||
# least the smoke tests still pass.
|
||||
- test-llvm15-go119
|
||||
# This tests LLVM 19 support when linking against system libraries.
|
||||
- test-llvm19-go123
|
||||
- test-llvm19-go124
|
||||
|
||||
@@ -39,7 +39,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.24'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
@@ -143,7 +143,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.24'
|
||||
cache: true
|
||||
- name: Build TinyGo (LLVM ${{ matrix.version }})
|
||||
run: go install -tags=llvm${{ matrix.version }}
|
||||
|
||||
+11
-10
@@ -18,7 +18,7 @@ jobs:
|
||||
# statically linked binary.
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: golang:1.23-alpine
|
||||
image: golang:1.24-alpine
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
@@ -146,12 +146,12 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.24'
|
||||
cache: true
|
||||
- name: Install wasmtime
|
||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||
with:
|
||||
version: "19.0.1"
|
||||
version: "29.0.1"
|
||||
- name: Install wasm-tools
|
||||
uses: bytecodealliance/actions/wasm-tools/setup@v1
|
||||
- name: Download release artifact
|
||||
@@ -165,11 +165,12 @@ jobs:
|
||||
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
|
||||
- run: make tinygo-test-wasip1-fast
|
||||
- run: make tinygo-test-wasip2-fast
|
||||
- run: make tinygo-test-wasm
|
||||
- run: make smoketest
|
||||
assert-test-linux:
|
||||
# Run all tests that can run on Linux, with LLVM assertions enabled to catch
|
||||
# potential bugs.
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -189,7 +190,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.24'
|
||||
cache: true
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
@@ -198,7 +199,7 @@ jobs:
|
||||
- name: Install wasmtime
|
||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||
with:
|
||||
version: "19.0.1"
|
||||
version: "29.0.1"
|
||||
- name: Setup `wasm-tools`
|
||||
uses: bytecodealliance/actions/wasm-tools/setup@v1
|
||||
- name: Restore LLVM source cache
|
||||
@@ -277,7 +278,7 @@ jobs:
|
||||
run: make tinygo-test
|
||||
- run: make smoketest
|
||||
- run: make wasmtest
|
||||
- run: make tinygo-baremetal
|
||||
- run: make tinygo-test-baremetal
|
||||
build-linux-cross:
|
||||
# Build ARM Linux binaries, ready for release.
|
||||
# This intentionally uses an older Linux image, so that we compile against
|
||||
@@ -297,7 +298,7 @@ jobs:
|
||||
- goarch: arm
|
||||
toolchain: arm-linux-gnueabihf
|
||||
libc: armhf
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04 # note: use the oldest image available! (see above)
|
||||
needs: build-linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -315,7 +316,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.24'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v4
|
||||
@@ -346,7 +347,7 @@ jobs:
|
||||
uses: actions/cache/restore@v4
|
||||
id: cache-llvm-build
|
||||
with:
|
||||
key: llvm-build-19-linux-${{ matrix.goarch }}-v2
|
||||
key: llvm-build-19-linux-${{ matrix.goarch }}-v3
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
|
||||
@@ -11,6 +11,7 @@ name: LLVM
|
||||
on:
|
||||
push:
|
||||
branches: [ build-llvm-image ]
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.24'
|
||||
cache: true
|
||||
- name: Restore cached LLVM source
|
||||
uses: actions/cache/restore@v4
|
||||
@@ -109,7 +109,7 @@ jobs:
|
||||
C:/Users/runneradmin/go/pkg/mod
|
||||
- name: Install wasmtime
|
||||
run: |
|
||||
scoop install wasmtime@14.0.4
|
||||
scoop install wasmtime@29.0.1
|
||||
- name: make gen-device
|
||||
run: make -j3 gen-device
|
||||
- name: Test TinyGo
|
||||
@@ -156,7 +156,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.24'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -186,7 +186,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.24'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
@@ -216,13 +216,13 @@ jobs:
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
scoop install binaryen && scoop install wasmtime@14.0.4
|
||||
scoop install binaryen && scoop install wasmtime@29.0.1
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.23'
|
||||
go-version: '1.24'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
@@ -1,3 +1,72 @@
|
||||
0.36.0
|
||||
---
|
||||
* **general**
|
||||
- add initial Go 1.24 support
|
||||
- add support for LLVM 19
|
||||
- update license for 2025
|
||||
- make small corrections for README regarding wasm
|
||||
- use GOOS and GOARCH for building wasm simulated boards
|
||||
- only infer target for wasm when GOOS and GOARCH are set correctly, not just based on file extension
|
||||
- add test-corpus-wasip2
|
||||
- use older image for cross-compiling builds
|
||||
- update Linux builds to run on ubuntu-latest since 20.04 is being retired
|
||||
- ensure build output directory is created
|
||||
- add NoSandbox flag to chrome headless that is run during WASM tests, since this is now required for Ubuntu 23+ and we are using Ubuntu 24+ when running Github Actions
|
||||
- update wasmtime used for CI to 29.0.1 to fix issue with install during CI tests
|
||||
- update to use `Get-CimInstance` as `wmic` is being deprecated on WIndows
|
||||
- remove unnecessary executable permissions
|
||||
- `goenv`: update to new v0.36.0 development version
|
||||
* **compiler**
|
||||
- `builder`: fix parsing of external ld.lld error messages
|
||||
- `cgo`: mangle identifier names
|
||||
- `interp`: correctly mark functions as modifying memory
|
||||
- add buildmode=wasi-legacy to support existing base of users who expected the older behavior for wasi modules to not return an exit code as if they were reactors
|
||||
* **standard library**
|
||||
- `crypto/tls`: add Dialer.DialContext() to fix websocket client
|
||||
- `crypto/tls`: add VersionTLS constants and VersionName(version uint16) method that turns it into a string, copied from big go
|
||||
- `internal/syscall/unix`: use our own version of this package
|
||||
- `machine`: replace hard-coded cpu frequencies on rp2xxx
|
||||
- `machine`: bump rp2350 CPUFrequency to 150 MHz
|
||||
- `machine`: compute rp2 clock dividers from crystal and target frequency
|
||||
- `machine`: remove bytes package dependency in flash code
|
||||
- `machine/usb/descriptor`: avoid bytes package
|
||||
- `net`: update to latest submodule with httptest subpackage and ResolveIPAddress implementation
|
||||
- `os`: add File.Chdir support
|
||||
- `os`: implement stub Chdir for non-OS systems
|
||||
- `os/file`: add file.Chmod
|
||||
- `reflect`: implement Value.Equal
|
||||
- `runtime`: add FIPS helper functions
|
||||
- `runtime`: manually initialize xorshift state
|
||||
- `sync`: move Mutex to internal/task
|
||||
- `syscall`: add wasip1 RandomGet
|
||||
- `testing`: add Chdir
|
||||
- `wasip2`: add stubs to get internal/syscall/unix to work
|
||||
* **fixes**
|
||||
- correctly handle calls for GetRNG() when being made from nrf devices with SoftDevice enabled
|
||||
- fix stm32f103 ADC
|
||||
- `wasm`: correctly handle id lookup for finalizeRef call
|
||||
- `wasm`: avoid total failure on wasm finalizer call
|
||||
- `wasm`: convert offset as signed int into unsigned int in syscall/js.stringVal in wasm_exec.js
|
||||
* **targets**
|
||||
- rp2350: add pll generalized solution; fix ADC handles; pwm period fix
|
||||
- rp2350: extending support to include the rp2350b
|
||||
- rp2350: cleanup: unexport internal USB and clock package variable, consts and types
|
||||
- nrf: make ADC resolution changeable
|
||||
- turn on GC for TKey1 device, since it does in fact work
|
||||
- match Pico2 stack size to Pico
|
||||
* **boards**
|
||||
- add support for Pimoroni Pico Plus2
|
||||
- add target for pico2-w board
|
||||
- add comboat_fw tag for elecrow W5 boards with Combo-AT Wifi firmware
|
||||
- add support for Elecrow Pico rp2350 W5 boards
|
||||
- add support for Elecrow Pico rp2040 W5 boards
|
||||
- add support for NRF51 HW-651
|
||||
- add support for esp32c3-supermini
|
||||
- add support for waveshare-rp2040-tiny
|
||||
* **examples**
|
||||
- add naive debouncing for pininterrupt example
|
||||
|
||||
|
||||
0.35.0
|
||||
---
|
||||
* **general**
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||
FROM golang:1.23 AS tinygo-llvm
|
||||
FROM golang:1.24 AS tinygo-llvm
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y apt-utils make cmake clang-15 ninja-build && \
|
||||
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
|
||||
|
||||
# tinygo-compiler copies the compiler build over to a base Go container (without
|
||||
# all the build tools etc).
|
||||
FROM golang:1.23 AS tinygo-compiler
|
||||
FROM golang:1.24 AS tinygo-compiler
|
||||
|
||||
# Copy tinygo build.
|
||||
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
|
||||
|
||||
+67
-23
@@ -309,11 +309,9 @@ TEST_PACKAGES_FAST = \
|
||||
container/heap \
|
||||
container/list \
|
||||
container/ring \
|
||||
crypto/des \
|
||||
crypto/ecdsa \
|
||||
crypto/elliptic \
|
||||
crypto/md5 \
|
||||
crypto/rc4 \
|
||||
crypto/sha1 \
|
||||
crypto/sha256 \
|
||||
crypto/sha512 \
|
||||
@@ -355,17 +353,11 @@ TEST_PACKAGES_FAST = \
|
||||
unique \
|
||||
$(nil)
|
||||
|
||||
# Assume this will go away before Go2, so only check minor version.
|
||||
ifeq ($(filter $(shell $(GO) env GOVERSION | cut -f 2 -d.), 16 17 18), )
|
||||
TEST_PACKAGES_FAST += crypto/internal/nistec/fiat
|
||||
else
|
||||
TEST_PACKAGES_FAST += crypto/elliptic/internal/fiat
|
||||
endif
|
||||
|
||||
# archive/zip requires os.ReadAt, which is not yet supported on windows
|
||||
# bytes requires mmap
|
||||
# compress/flate appears to hang on wasi
|
||||
# crypto/aes fails on wasi, needs panic()/recover()
|
||||
# crypto/des fails on wasi, needs panic()/recover()
|
||||
# crypto/hmac fails on wasi, it exits with a "slice out of range" panic
|
||||
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows
|
||||
# image requires recover(), which is not yet supported on wasi
|
||||
@@ -386,6 +378,7 @@ TEST_PACKAGES_LINUX := \
|
||||
archive/zip \
|
||||
compress/flate \
|
||||
crypto/aes \
|
||||
crypto/des \
|
||||
crypto/hmac \
|
||||
debug/dwarf \
|
||||
debug/plan9obj \
|
||||
@@ -405,14 +398,52 @@ TEST_PACKAGES_LINUX := \
|
||||
|
||||
TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
|
||||
|
||||
# os/user requires t.Skip() support
|
||||
TEST_PACKAGES_WINDOWS := \
|
||||
compress/flate \
|
||||
crypto/des \
|
||||
crypto/hmac \
|
||||
os/user \
|
||||
strconv \
|
||||
text/template/parse \
|
||||
$(nil)
|
||||
|
||||
|
||||
# These packages cannot be tested on wasm, mostly because these tests assume a
|
||||
# working filesystem. This could perhaps be fixed, by supporting filesystem
|
||||
# access when running inside Node.js.
|
||||
TEST_PACKAGES_WASM = $(filter-out $(TEST_PACKAGES_NONWASM), $(TEST_PACKAGES_FAST))
|
||||
TEST_PACKAGES_NONWASM = \
|
||||
compress/lzw \
|
||||
compress/zlib \
|
||||
crypto/ecdsa \
|
||||
debug/macho \
|
||||
embed/internal/embedtest \
|
||||
go/format \
|
||||
os \
|
||||
testing \
|
||||
$(nil)
|
||||
|
||||
# These packages cannot be tested on baremetal.
|
||||
#
|
||||
# Some reasons why the tests don't pass on baremetal:
|
||||
#
|
||||
# * No filesystem is available, so packages like compress/zlib can't be tested
|
||||
# (just like wasm).
|
||||
# * picolibc math functions apparently are less precise, the math package
|
||||
# fails on baremetal.
|
||||
# * Some packages fail or hang for an unknown reason, this should be
|
||||
# investigated and fixed.
|
||||
TEST_PACKAGES_BAREMETAL = $(filter-out $(TEST_PACKAGES_NONBAREMETAL), $(TEST_PACKAGES_FAST))
|
||||
TEST_PACKAGES_NONBAREMETAL = \
|
||||
$(TEST_PACKAGES_NONWASM) \
|
||||
crypto/elliptic \
|
||||
math \
|
||||
reflect \
|
||||
encoding/asn1 \
|
||||
encoding/base32 \
|
||||
go/ast \
|
||||
$(nil)
|
||||
|
||||
# Report platforms on which each standard library package is known to pass tests
|
||||
jointmp := $(shell echo /tmp/join.$$$$)
|
||||
report-stdlib-tests-pass:
|
||||
@@ -456,6 +487,8 @@ tinygo-bench-fast:
|
||||
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST)
|
||||
|
||||
# Same thing, except for wasi rather than the current platform.
|
||||
tinygo-test-wasm:
|
||||
$(TINYGO) test -target wasm $(TEST_PACKAGES_WASM)
|
||||
tinygo-test-wasi:
|
||||
$(TINYGO) test -target wasip1 $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||
tinygo-test-wasip1:
|
||||
@@ -490,6 +523,10 @@ tinygo-bench-wasip2:
|
||||
tinygo-bench-wasip2-fast:
|
||||
$(TINYGO) test -target wasip2 -bench . $(TEST_PACKAGES_FAST)
|
||||
|
||||
# Run tests on riscv-qemu since that one provides a large amount of memory.
|
||||
tinygo-test-baremetal:
|
||||
$(TINYGO) test -target riscv-qemu $(TEST_PACKAGES_BAREMETAL)
|
||||
|
||||
# Test external packages in a large corpus.
|
||||
test-corpus:
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml
|
||||
@@ -497,11 +534,8 @@ test-corpus-fast:
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus -short . -corpus=testdata/corpus.yaml
|
||||
test-corpus-wasi: wasi-libc
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml -target=wasip1
|
||||
|
||||
tinygo-baremetal:
|
||||
# Regression tests that run on a baremetal target and don't fit in either main_test.go or smoketest.
|
||||
# regression test for #2666: e.g. encoding/hex must pass on baremetal
|
||||
$(TINYGO) test -target cortex-m-qemu encoding/hex
|
||||
test-corpus-wasip2: wasi-libc
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml -target=wasip2
|
||||
|
||||
.PHONY: testchdir
|
||||
testchdir:
|
||||
@@ -523,6 +557,8 @@ smoketest: testchdir
|
||||
# regression test for #2563
|
||||
cd tests/os/smoke && $(TINYGO) test -c -target=pybadge && rm smoke.test
|
||||
# test all examples (except pwm)
|
||||
$(TINYGO) build -size short -o test.hex -target=pga2350 examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/adc
|
||||
@@ -571,21 +607,23 @@ smoketest: testchdir
|
||||
@$(MD5SUM) test.hex
|
||||
# test simulated boards on play.tinygo.org
|
||||
ifneq ($(WASM), 0)
|
||||
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=hifive1b examples/blinky1
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=hifive1b examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=reelboard examples/blinky1
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=reelboard examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=microbit examples/microbit-blink
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=microbit examples/microbit-blink
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=circuitplay_express examples/blinky1
|
||||
GOOS=js GOARCH=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
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=circuitplay_bluefruit examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=mch2022 examples/machinetest
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=mch2022 examples/machinetest
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -size short -o test.wasm -tags=gopher_badge examples/blinky1
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=gopher_badge examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
GOOS=js GOARCH=wasm $(TINYGO) build -size short -o test.wasm -tags=pico examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
endif
|
||||
# test all targets/boards
|
||||
@@ -745,6 +783,8 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=tiny2350 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pico-plus2 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=waveshare-rp2040-tiny examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
# test pwm
|
||||
@@ -867,6 +907,10 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=elecrow-rp2350 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=hw-651 examples/machinetest
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=hw-651-s110v8 examples/machinetest
|
||||
@$(MD5SUM) test.hex
|
||||
ifneq ($(WASM), 0)
|
||||
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/export
|
||||
$(TINYGO) build -size short -o wasm.wasm -target=wasm examples/wasm/main
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Copyright (c) 2018-2023 The TinyGo Authors. All rights reserved.
|
||||
Copyright (c) 2018-2025 The TinyGo Authors. All rights reserved.
|
||||
|
||||
TinyGo includes portions of the Go standard library.
|
||||
Copyright (c) 2009-2023 The Go Authors. All rights reserved.
|
||||
Copyright (c) 2009-2024 The Go Authors. All rights reserved.
|
||||
|
||||
TinyGo includes portions of LLVM, which is under the Apache License v2.0 with
|
||||
LLVM Exceptions. See https://llvm.org/LICENSE.txt for license information.
|
||||
|
||||
@@ -48,20 +48,22 @@ Here is a small TinyGo program for use by a WASI host application:
|
||||
```go
|
||||
package main
|
||||
|
||||
//go:wasm-module yourmodulename
|
||||
//export add
|
||||
//go:wasmexport add
|
||||
func add(x, y uint32) uint32 {
|
||||
return x + y
|
||||
}
|
||||
|
||||
// main is required for the `wasip1` target, even if it isn't used.
|
||||
func main() {}
|
||||
```
|
||||
|
||||
This compiles the above TinyGo program for use on any WASI runtime:
|
||||
This compiles the above TinyGo program for use on any WASI Preview 1 runtime:
|
||||
|
||||
```shell
|
||||
tinygo build -o main.wasm -target=wasip1 main.go
|
||||
tinygo build -buildmode=c-shared -o add.wasm -target=wasip1 add.go
|
||||
```
|
||||
|
||||
You can also use the same syntax as Go 1.24+:
|
||||
|
||||
```shell
|
||||
GOARCH=wasip1 GOOS=wasm tinygo build -buildmode=c-shared -o add.wasm add.go
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -604,6 +604,11 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
},
|
||||
}
|
||||
|
||||
// Create the output directory, if needed
|
||||
if err := os.MkdirAll(filepath.Dir(outpath), 0777); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Check whether we only need to create an object file.
|
||||
// If so, we don't need to link anything and will be finished quickly.
|
||||
outext := filepath.Ext(outpath)
|
||||
@@ -667,6 +672,16 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
ldflags = append(ldflags, "--no-entry")
|
||||
}
|
||||
|
||||
if config.Options.BuildMode == "wasi-legacy" {
|
||||
if !strings.HasPrefix(config.Triple(), "wasm32-") {
|
||||
return result, fmt.Errorf("buildmode wasi-legacy is only supported on wasm")
|
||||
}
|
||||
|
||||
if config.Options.Scheduler != "none" {
|
||||
return result, fmt.Errorf("buildmode wasi-legacy only supports scheduler=none")
|
||||
}
|
||||
}
|
||||
|
||||
// Add compiler-rt dependency if needed. Usually this is a simple load from
|
||||
// a cache.
|
||||
if config.Target.RTLib == "compiler-rt" {
|
||||
|
||||
@@ -69,7 +69,6 @@ func TestClangAttributes(t *testing.T) {
|
||||
{GOOS: "darwin", GOARCH: "arm64"},
|
||||
{GOOS: "windows", GOARCH: "amd64"},
|
||||
{GOOS: "windows", GOARCH: "arm64"},
|
||||
{GOOS: "wasip1", GOARCH: "wasm"},
|
||||
} {
|
||||
name := "GOOS=" + options.GOOS + ",GOARCH=" + options.GOARCH
|
||||
if options.GOARCH == "arm" {
|
||||
|
||||
+2
-2
@@ -26,7 +26,7 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
||||
|
||||
// Version range supported by TinyGo.
|
||||
const minorMin = 19
|
||||
const minorMax = 23
|
||||
const minorMax = 24
|
||||
|
||||
// Check that we support this Go toolchain version.
|
||||
gorootMajor, gorootMinor, err := goenv.GetGorootVersion()
|
||||
@@ -36,7 +36,7 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
||||
if gorootMajor != 1 || gorootMinor < minorMin || gorootMinor > minorMax {
|
||||
// Note: when this gets updated, also update the Go compatibility matrix:
|
||||
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
|
||||
return nil, fmt.Errorf("requires go version 1.19 through 1.23, got go%d.%d", gorootMajor, gorootMinor)
|
||||
return nil, fmt.Errorf("requires go version 1.%d through 1.%d, got go%d.%d", minorMin, minorMax, gorootMajor, gorootMinor)
|
||||
}
|
||||
|
||||
// Check that the Go toolchain version isn't too new, if we haven't been
|
||||
|
||||
@@ -113,7 +113,6 @@ var libMusl = Library{
|
||||
librarySources: func(target string) ([]string, error) {
|
||||
arch := compileopts.MuslArchitecture(target)
|
||||
globs := []string{
|
||||
"conf/*.c",
|
||||
"env/*.c",
|
||||
"errno/*.c",
|
||||
"exit/*.c",
|
||||
|
||||
+2
-2
@@ -490,9 +490,9 @@ func loadProgramSize(path string, packagePathMap map[string]string) (*programSiz
|
||||
continue
|
||||
}
|
||||
if section.Type == elf.SHT_NOBITS {
|
||||
if section.Name == ".stack" || section.Name == ".stack1" {
|
||||
if section.Name == ".stack" {
|
||||
// TinyGo emits stack sections on microcontroller using the
|
||||
// ".stack" (or ".stack1") name.
|
||||
// ".stack" name.
|
||||
// This is a bit ugly, but I don't think there is a way to
|
||||
// mark the stack section in a linker script.
|
||||
sections = append(sections, memorySection{
|
||||
|
||||
@@ -43,8 +43,8 @@ func TestBinarySize(t *testing.T) {
|
||||
tests := []sizeTest{
|
||||
// microcontrollers
|
||||
{"hifive1b", "examples/echo", 4560, 280, 0, 2268},
|
||||
{"microbit", "examples/serial", 2908, 388, 8, 2272},
|
||||
{"wioterminal", "examples/pininterrupt", 7293, 1487, 116, 6912},
|
||||
{"microbit", "examples/serial", 2916, 388, 8, 2272},
|
||||
{"wioterminal", "examples/pininterrupt", 7359, 1489, 116, 6912},
|
||||
|
||||
// TODO: also check wasm. Right now this is difficult, because
|
||||
// wasm binaries are run through wasm-opt and therefore the
|
||||
|
||||
+45
-64
@@ -92,18 +92,18 @@ type noescapingFunc struct {
|
||||
// cgoAliases list type aliases between Go and C, for types that are equivalent
|
||||
// in both languages. See addTypeAliases.
|
||||
var cgoAliases = map[string]string{
|
||||
"C.int8_t": "int8",
|
||||
"C.int16_t": "int16",
|
||||
"C.int32_t": "int32",
|
||||
"C.int64_t": "int64",
|
||||
"C.uint8_t": "uint8",
|
||||
"C.uint16_t": "uint16",
|
||||
"C.uint32_t": "uint32",
|
||||
"C.uint64_t": "uint64",
|
||||
"C.uintptr_t": "uintptr",
|
||||
"C.float": "float32",
|
||||
"C.double": "float64",
|
||||
"C._Bool": "bool",
|
||||
"_Cgo_int8_t": "int8",
|
||||
"_Cgo_int16_t": "int16",
|
||||
"_Cgo_int32_t": "int32",
|
||||
"_Cgo_int64_t": "int64",
|
||||
"_Cgo_uint8_t": "uint8",
|
||||
"_Cgo_uint16_t": "uint16",
|
||||
"_Cgo_uint32_t": "uint32",
|
||||
"_Cgo_uint64_t": "uint64",
|
||||
"_Cgo_uintptr_t": "uintptr",
|
||||
"_Cgo_float": "float32",
|
||||
"_Cgo_double": "float64",
|
||||
"_Cgo__Bool": "bool",
|
||||
}
|
||||
|
||||
// builtinAliases are handled specially because they only exist on the Go side
|
||||
@@ -145,48 +145,46 @@ typedef unsigned long long _Cgo_ulonglong;
|
||||
// The string/bytes functions below implement C.CString etc. To make sure the
|
||||
// runtime doesn't need to know the C int type, lengths are converted to uintptr
|
||||
// first.
|
||||
// These functions will be modified to get a "C." prefix, so the source below
|
||||
// doesn't reflect the final AST.
|
||||
const generatedGoFilePrefixBase = `
|
||||
import "syscall"
|
||||
import "unsafe"
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
//go:linkname C.CString runtime.cgo_CString
|
||||
func CString(string) *C.char
|
||||
//go:linkname _Cgo_CString runtime.cgo_CString
|
||||
func _Cgo_CString(string) *_Cgo_char
|
||||
|
||||
//go:linkname C.GoString runtime.cgo_GoString
|
||||
func GoString(*C.char) string
|
||||
//go:linkname _Cgo_GoString runtime.cgo_GoString
|
||||
func _Cgo_GoString(*_Cgo_char) string
|
||||
|
||||
//go:linkname C.__GoStringN runtime.cgo_GoStringN
|
||||
func __GoStringN(*C.char, uintptr) string
|
||||
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN
|
||||
func _Cgo___GoStringN(*_Cgo_char, uintptr) string
|
||||
|
||||
func GoStringN(cstr *C.char, length C.int) string {
|
||||
return C.__GoStringN(cstr, uintptr(length))
|
||||
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string {
|
||||
return _Cgo___GoStringN(cstr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__GoBytes runtime.cgo_GoBytes
|
||||
func __GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes
|
||||
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
|
||||
func GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
return C.__GoBytes(ptr, uintptr(length))
|
||||
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte {
|
||||
return _Cgo___GoBytes(ptr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__CBytes runtime.cgo_CBytes
|
||||
func __CBytes([]byte) unsafe.Pointer
|
||||
//go:linkname _Cgo___CBytes runtime.cgo_CBytes
|
||||
func _Cgo___CBytes([]byte) unsafe.Pointer
|
||||
|
||||
func CBytes(b []byte) unsafe.Pointer {
|
||||
return C.__CBytes(b)
|
||||
func _Cgo_CBytes(b []byte) unsafe.Pointer {
|
||||
return _Cgo___CBytes(b)
|
||||
}
|
||||
|
||||
//go:linkname C.__get_errno_num runtime.cgo_errno
|
||||
func __get_errno_num() uintptr
|
||||
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
|
||||
func _Cgo___get_errno_num() uintptr
|
||||
`
|
||||
|
||||
const generatedGoFilePrefixOther = generatedGoFilePrefixBase + `
|
||||
func __get_errno() error {
|
||||
return syscall.Errno(C.__get_errno_num())
|
||||
func _Cgo___get_errno() error {
|
||||
return syscall.Errno(_Cgo___get_errno_num())
|
||||
}
|
||||
`
|
||||
|
||||
@@ -197,7 +195,7 @@ func __get_errno() error {
|
||||
// map the errno values to match the values in the syscall package.
|
||||
// Source of the errno values: lib/mingw-w64/mingw-w64-headers/crt/errno.h
|
||||
const generatedGoFilePrefixWindows = generatedGoFilePrefixBase + `
|
||||
var __errno_mapping = [...]syscall.Errno{
|
||||
var _Cgo___errno_mapping = [...]syscall.Errno{
|
||||
1: syscall.EPERM,
|
||||
2: syscall.ENOENT,
|
||||
3: syscall.ESRCH,
|
||||
@@ -238,10 +236,10 @@ var __errno_mapping = [...]syscall.Errno{
|
||||
42: syscall.EILSEQ,
|
||||
}
|
||||
|
||||
func __get_errno() error {
|
||||
num := C.__get_errno_num()
|
||||
if num < uintptr(len(__errno_mapping)) {
|
||||
if mapped := __errno_mapping[num]; mapped != 0 {
|
||||
func _Cgo___get_errno() error {
|
||||
num := _Cgo___get_errno_num()
|
||||
if num < uintptr(len(_Cgo___errno_mapping)) {
|
||||
if mapped := _Cgo___errno_mapping[num]; mapped != 0 {
|
||||
return mapped
|
||||
}
|
||||
}
|
||||
@@ -304,23 +302,6 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
||||
// If the Comments field is not set to nil, the go/format package will get
|
||||
// confused about where comments should go.
|
||||
p.generated.Comments = nil
|
||||
// Adjust some of the functions in there.
|
||||
for _, decl := range p.generated.Decls {
|
||||
switch decl := decl.(type) {
|
||||
case *ast.FuncDecl:
|
||||
switch decl.Name.Name {
|
||||
case "CString", "GoString", "GoStringN", "__GoStringN", "GoBytes", "__GoBytes", "CBytes", "__CBytes", "__get_errno_num", "__get_errno", "__errno_mapping":
|
||||
// Adjust the name to have a "C." prefix so it is correctly
|
||||
// resolved.
|
||||
decl.Name.Name = "C." + decl.Name.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
// Patch some types, for example *C.char in C.CString.
|
||||
cf := p.newCGoFile(nil, -1) // dummy *cgoFile for the walker
|
||||
astutil.Apply(p.generated, func(cursor *astutil.Cursor) bool {
|
||||
return cf.walker(cursor, nil)
|
||||
}, nil)
|
||||
|
||||
// Find `import "C"` C fragments in the file.
|
||||
p.cgoHeaders = make([]string, len(files)) // combined CGo header fragment for each file
|
||||
@@ -399,7 +380,7 @@ func Process(files []*ast.File, dir, importPath string, fset *token.FileSet, cfl
|
||||
Tok: token.TYPE,
|
||||
}
|
||||
for _, name := range builtinAliases {
|
||||
typeSpec := p.getIntegerType("C."+name, names["_Cgo_"+name])
|
||||
typeSpec := p.getIntegerType("_Cgo_"+name, names["_Cgo_"+name])
|
||||
gen.Specs = append(gen.Specs, typeSpec)
|
||||
}
|
||||
p.generated.Decls = append(p.generated.Decls, gen)
|
||||
@@ -1272,7 +1253,7 @@ func (p *cgoPackage) getUnnamedDeclName(prefix string, itf interface{}) string {
|
||||
func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) string {
|
||||
// Some types are defined in stdint.h and map directly to a particular Go
|
||||
// type.
|
||||
if alias := cgoAliases["C."+name]; alias != "" {
|
||||
if alias := cgoAliases["_Cgo_"+name]; alias != "" {
|
||||
return alias
|
||||
}
|
||||
node := f.getASTDeclNode(name, found)
|
||||
@@ -1282,7 +1263,7 @@ func (f *cgoFile) getASTDeclName(name string, found clangCursor, iscall bool) st
|
||||
}
|
||||
return node.Name.Name
|
||||
}
|
||||
return "C." + name
|
||||
return "_Cgo_" + name
|
||||
}
|
||||
|
||||
// getASTDeclNode will declare the given C AST node (if not already defined) and
|
||||
@@ -1382,8 +1363,8 @@ extern __typeof(%s) %s __attribute__((alias(%#v)));
|
||||
case *elaboratedTypeInfo:
|
||||
// Add struct bitfields.
|
||||
for _, bitfield := range elaboratedType.bitfields {
|
||||
f.createBitfieldGetter(bitfield, "C."+name)
|
||||
f.createBitfieldSetter(bitfield, "C."+name)
|
||||
f.createBitfieldGetter(bitfield, "_Cgo_"+name)
|
||||
f.createBitfieldSetter(bitfield, "_Cgo_"+name)
|
||||
}
|
||||
if elaboratedType.unionSize != 0 {
|
||||
// Create union getters/setters.
|
||||
@@ -1392,7 +1373,7 @@ extern __typeof(%s) %s __attribute__((alias(%#v)));
|
||||
f.addError(elaboratedType.pos, fmt.Sprintf("union must have field with a single name, it has %d names", len(field.Names)))
|
||||
continue
|
||||
}
|
||||
f.createUnionAccessor(field, "C."+name)
|
||||
f.createUnionAccessor(field, "_Cgo_"+name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1441,7 +1422,7 @@ func (f *cgoFile) walker(cursor *astutil.Cursor, names map[string]clangCursor) b
|
||||
node.Rhs = append(node.Rhs, &ast.CallExpr{
|
||||
Fun: &ast.Ident{
|
||||
NamePos: node.Lhs[1].End(),
|
||||
Name: "C.__get_errno",
|
||||
Name: "_Cgo___get_errno",
|
||||
},
|
||||
})
|
||||
}
|
||||
@@ -1466,7 +1447,7 @@ func (f *cgoFile) walker(cursor *astutil.Cursor, names map[string]clangCursor) b
|
||||
return true
|
||||
}
|
||||
if x.Name == "C" {
|
||||
name := "C." + node.Sel.Name
|
||||
name := "_Cgo_" + node.Sel.Name
|
||||
if found, ok := names[node.Sel.Name]; ok {
|
||||
name = f.getASTDeclName(node.Sel.Name, found, false)
|
||||
}
|
||||
|
||||
+27
-27
@@ -219,7 +219,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
numArgs := int(C.tinygo_clang_Cursor_getNumArguments(c))
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Fun,
|
||||
Name: "C." + name,
|
||||
Name: "_Cgo_" + name,
|
||||
}
|
||||
exportName := name
|
||||
localName := name
|
||||
@@ -257,7 +257,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
},
|
||||
Name: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: "C." + localName,
|
||||
Name: "_Cgo_" + localName,
|
||||
Obj: obj,
|
||||
},
|
||||
Type: &ast.FuncType{
|
||||
@@ -319,7 +319,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
return decl, stringSignature
|
||||
case C.CXCursor_StructDecl, C.CXCursor_UnionDecl:
|
||||
typ := f.makeASTRecordType(c, pos)
|
||||
typeName := "C." + name
|
||||
typeName := "_Cgo_" + name
|
||||
typeExpr := typ.typeExpr
|
||||
if typ.unionSize != 0 {
|
||||
// Convert to a single-field struct type.
|
||||
@@ -340,7 +340,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
obj.Decl = typeSpec
|
||||
return typeSpec, typ
|
||||
case C.CXCursor_TypedefDecl:
|
||||
typeName := "C." + name
|
||||
typeName := "_Cgo_" + name
|
||||
underlyingType := C.tinygo_clang_getTypedefDeclUnderlyingType(c)
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Typ,
|
||||
@@ -378,12 +378,12 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
}
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Var,
|
||||
Name: "C." + name,
|
||||
Name: "_Cgo_" + name,
|
||||
}
|
||||
valueSpec := &ast.ValueSpec{
|
||||
Names: []*ast.Ident{{
|
||||
NamePos: pos,
|
||||
Name: "C." + name,
|
||||
Name: "_Cgo_" + name,
|
||||
Obj: obj,
|
||||
}},
|
||||
Type: typeExpr,
|
||||
@@ -407,12 +407,12 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
}
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Con,
|
||||
Name: "C." + name,
|
||||
Name: "_Cgo_" + name,
|
||||
}
|
||||
valueSpec := &ast.ValueSpec{
|
||||
Names: []*ast.Ident{{
|
||||
NamePos: pos,
|
||||
Name: "C." + name,
|
||||
Name: "_Cgo_" + name,
|
||||
Obj: obj,
|
||||
}},
|
||||
Values: []ast.Expr{expr},
|
||||
@@ -423,7 +423,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
case C.CXCursor_EnumDecl:
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Typ,
|
||||
Name: "C." + name,
|
||||
Name: "_Cgo_" + name,
|
||||
}
|
||||
underlying := C.tinygo_clang_getEnumDeclIntegerType(c)
|
||||
// TODO: gc's CGo implementation uses types such as `uint32` for enums
|
||||
@@ -431,7 +431,7 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
typeSpec := &ast.TypeSpec{
|
||||
Name: &ast.Ident{
|
||||
NamePos: pos,
|
||||
Name: "C." + name,
|
||||
Name: "_Cgo_" + name,
|
||||
Obj: obj,
|
||||
},
|
||||
Assign: pos,
|
||||
@@ -454,12 +454,12 @@ func (f *cgoFile) createASTNode(name string, c clangCursor) (ast.Node, any) {
|
||||
}
|
||||
obj := &ast.Object{
|
||||
Kind: ast.Con,
|
||||
Name: "C." + name,
|
||||
Name: "_Cgo_" + name,
|
||||
}
|
||||
valueSpec := &ast.ValueSpec{
|
||||
Names: []*ast.Ident{{
|
||||
NamePos: pos,
|
||||
Name: "C." + name,
|
||||
Name: "_Cgo_" + name,
|
||||
Obj: obj,
|
||||
}},
|
||||
Values: []ast.Expr{expr},
|
||||
@@ -745,27 +745,27 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||
var typeName string
|
||||
switch typ.kind {
|
||||
case C.CXType_Char_S, C.CXType_Char_U:
|
||||
typeName = "C.char"
|
||||
typeName = "_Cgo_char"
|
||||
case C.CXType_SChar:
|
||||
typeName = "C.schar"
|
||||
typeName = "_Cgo_schar"
|
||||
case C.CXType_UChar:
|
||||
typeName = "C.uchar"
|
||||
typeName = "_Cgo_uchar"
|
||||
case C.CXType_Short:
|
||||
typeName = "C.short"
|
||||
typeName = "_Cgo_short"
|
||||
case C.CXType_UShort:
|
||||
typeName = "C.ushort"
|
||||
typeName = "_Cgo_ushort"
|
||||
case C.CXType_Int:
|
||||
typeName = "C.int"
|
||||
typeName = "_Cgo_int"
|
||||
case C.CXType_UInt:
|
||||
typeName = "C.uint"
|
||||
typeName = "_Cgo_uint"
|
||||
case C.CXType_Long:
|
||||
typeName = "C.long"
|
||||
typeName = "_Cgo_long"
|
||||
case C.CXType_ULong:
|
||||
typeName = "C.ulong"
|
||||
typeName = "_Cgo_ulong"
|
||||
case C.CXType_LongLong:
|
||||
typeName = "C.longlong"
|
||||
typeName = "_Cgo_longlong"
|
||||
case C.CXType_ULongLong:
|
||||
typeName = "C.ulonglong"
|
||||
typeName = "_Cgo_ulonglong"
|
||||
case C.CXType_Bool:
|
||||
typeName = "bool"
|
||||
case C.CXType_Float, C.CXType_Double, C.CXType_LongDouble:
|
||||
@@ -896,7 +896,7 @@ func (f *cgoFile) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
|
||||
typeSpelling := getString(C.clang_getTypeSpelling(typ))
|
||||
typeKindSpelling := getString(C.clang_getTypeKindSpelling(typ.kind))
|
||||
f.addError(pos, fmt.Sprintf("unknown C type: %v (libclang type kind %s)", typeSpelling, typeKindSpelling))
|
||||
typeName = "C.<unknown>"
|
||||
typeName = "_Cgo_<unknown>"
|
||||
}
|
||||
return &ast.Ident{
|
||||
NamePos: pos,
|
||||
@@ -913,7 +913,7 @@ func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSp
|
||||
var goName string
|
||||
typeSize := C.clang_Type_getSizeOf(underlyingType)
|
||||
switch name {
|
||||
case "C.char":
|
||||
case "_Cgo_char":
|
||||
if typeSize != 1 {
|
||||
// This happens for some very special purpose architectures
|
||||
// (DSPs etc.) that are not currently targeted.
|
||||
@@ -926,7 +926,7 @@ func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSp
|
||||
case C.CXType_Char_U:
|
||||
goName = "uint8"
|
||||
}
|
||||
case "C.schar", "C.short", "C.int", "C.long", "C.longlong":
|
||||
case "_Cgo_schar", "_Cgo_short", "_Cgo_int", "_Cgo_long", "_Cgo_longlong":
|
||||
switch typeSize {
|
||||
case 1:
|
||||
goName = "int8"
|
||||
@@ -937,7 +937,7 @@ func (p *cgoPackage) getIntegerType(name string, cursor clangCursor) *ast.TypeSp
|
||||
case 8:
|
||||
goName = "int64"
|
||||
}
|
||||
case "C.uchar", "C.ushort", "C.uint", "C.ulong", "C.ulonglong":
|
||||
case "_Cgo_uchar", "_Cgo_ushort", "_Cgo_uint", "_Cgo_ulong", "_Cgo_ulonglong":
|
||||
switch typeSize {
|
||||
case 1:
|
||||
goName = "uint8"
|
||||
|
||||
Vendored
+31
-31
@@ -5,50 +5,50 @@ import "unsafe"
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
//go:linkname C.CString runtime.cgo_CString
|
||||
func C.CString(string) *C.char
|
||||
//go:linkname _Cgo_CString runtime.cgo_CString
|
||||
func _Cgo_CString(string) *_Cgo_char
|
||||
|
||||
//go:linkname C.GoString runtime.cgo_GoString
|
||||
func C.GoString(*C.char) string
|
||||
//go:linkname _Cgo_GoString runtime.cgo_GoString
|
||||
func _Cgo_GoString(*_Cgo_char) string
|
||||
|
||||
//go:linkname C.__GoStringN runtime.cgo_GoStringN
|
||||
func C.__GoStringN(*C.char, uintptr) string
|
||||
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN
|
||||
func _Cgo___GoStringN(*_Cgo_char, uintptr) string
|
||||
|
||||
func C.GoStringN(cstr *C.char, length C.int) string {
|
||||
return C.__GoStringN(cstr, uintptr(length))
|
||||
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string {
|
||||
return _Cgo___GoStringN(cstr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__GoBytes runtime.cgo_GoBytes
|
||||
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes
|
||||
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
|
||||
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
return C.__GoBytes(ptr, uintptr(length))
|
||||
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte {
|
||||
return _Cgo___GoBytes(ptr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__CBytes runtime.cgo_CBytes
|
||||
func C.__CBytes([]byte) unsafe.Pointer
|
||||
//go:linkname _Cgo___CBytes runtime.cgo_CBytes
|
||||
func _Cgo___CBytes([]byte) unsafe.Pointer
|
||||
|
||||
func C.CBytes(b []byte) unsafe.Pointer {
|
||||
return C.__CBytes(b)
|
||||
func _Cgo_CBytes(b []byte) unsafe.Pointer {
|
||||
return _Cgo___CBytes(b)
|
||||
}
|
||||
|
||||
//go:linkname C.__get_errno_num runtime.cgo_errno
|
||||
func C.__get_errno_num() uintptr
|
||||
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
|
||||
func _Cgo___get_errno_num() uintptr
|
||||
|
||||
func C.__get_errno() error {
|
||||
return syscall.Errno(C.__get_errno_num())
|
||||
func _Cgo___get_errno() error {
|
||||
return syscall.Errno(_Cgo___get_errno_num())
|
||||
}
|
||||
|
||||
type (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
C.uchar uint8
|
||||
C.short int16
|
||||
C.ushort uint16
|
||||
C.int int32
|
||||
C.uint uint32
|
||||
C.long int32
|
||||
C.ulong uint32
|
||||
C.longlong int64
|
||||
C.ulonglong uint64
|
||||
_Cgo_char uint8
|
||||
_Cgo_schar int8
|
||||
_Cgo_uchar uint8
|
||||
_Cgo_short int16
|
||||
_Cgo_ushort uint16
|
||||
_Cgo_int int32
|
||||
_Cgo_uint uint32
|
||||
_Cgo_long int32
|
||||
_Cgo_ulong uint32
|
||||
_Cgo_longlong int64
|
||||
_Cgo_ulonglong uint64
|
||||
)
|
||||
|
||||
Vendored
+38
-38
@@ -5,58 +5,58 @@ import "unsafe"
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
//go:linkname C.CString runtime.cgo_CString
|
||||
func C.CString(string) *C.char
|
||||
//go:linkname _Cgo_CString runtime.cgo_CString
|
||||
func _Cgo_CString(string) *_Cgo_char
|
||||
|
||||
//go:linkname C.GoString runtime.cgo_GoString
|
||||
func C.GoString(*C.char) string
|
||||
//go:linkname _Cgo_GoString runtime.cgo_GoString
|
||||
func _Cgo_GoString(*_Cgo_char) string
|
||||
|
||||
//go:linkname C.__GoStringN runtime.cgo_GoStringN
|
||||
func C.__GoStringN(*C.char, uintptr) string
|
||||
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN
|
||||
func _Cgo___GoStringN(*_Cgo_char, uintptr) string
|
||||
|
||||
func C.GoStringN(cstr *C.char, length C.int) string {
|
||||
return C.__GoStringN(cstr, uintptr(length))
|
||||
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string {
|
||||
return _Cgo___GoStringN(cstr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__GoBytes runtime.cgo_GoBytes
|
||||
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes
|
||||
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
|
||||
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
return C.__GoBytes(ptr, uintptr(length))
|
||||
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte {
|
||||
return _Cgo___GoBytes(ptr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__CBytes runtime.cgo_CBytes
|
||||
func C.__CBytes([]byte) unsafe.Pointer
|
||||
//go:linkname _Cgo___CBytes runtime.cgo_CBytes
|
||||
func _Cgo___CBytes([]byte) unsafe.Pointer
|
||||
|
||||
func C.CBytes(b []byte) unsafe.Pointer {
|
||||
return C.__CBytes(b)
|
||||
func _Cgo_CBytes(b []byte) unsafe.Pointer {
|
||||
return _Cgo___CBytes(b)
|
||||
}
|
||||
|
||||
//go:linkname C.__get_errno_num runtime.cgo_errno
|
||||
func C.__get_errno_num() uintptr
|
||||
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
|
||||
func _Cgo___get_errno_num() uintptr
|
||||
|
||||
func C.__get_errno() error {
|
||||
return syscall.Errno(C.__get_errno_num())
|
||||
func _Cgo___get_errno() error {
|
||||
return syscall.Errno(_Cgo___get_errno_num())
|
||||
}
|
||||
|
||||
type (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
C.uchar uint8
|
||||
C.short int16
|
||||
C.ushort uint16
|
||||
C.int int32
|
||||
C.uint uint32
|
||||
C.long int32
|
||||
C.ulong uint32
|
||||
C.longlong int64
|
||||
C.ulonglong uint64
|
||||
_Cgo_char uint8
|
||||
_Cgo_schar int8
|
||||
_Cgo_uchar uint8
|
||||
_Cgo_short int16
|
||||
_Cgo_ushort uint16
|
||||
_Cgo_int int32
|
||||
_Cgo_uint uint32
|
||||
_Cgo_long int32
|
||||
_Cgo_ulong uint32
|
||||
_Cgo_longlong int64
|
||||
_Cgo_ulonglong uint64
|
||||
)
|
||||
|
||||
const C.foo = 3
|
||||
const C.bar = C.foo
|
||||
const C.unreferenced = 4
|
||||
const C.referenced = C.unreferenced
|
||||
const C.fnlike_val = 5
|
||||
const C.square_val = (20 * 20)
|
||||
const C.add_val = (3 + 5)
|
||||
const _Cgo_foo = 3
|
||||
const _Cgo_bar = _Cgo_foo
|
||||
const _Cgo_unreferenced = 4
|
||||
const _Cgo_referenced = _Cgo_unreferenced
|
||||
const _Cgo_fnlike_val = 5
|
||||
const _Cgo_square_val = (20 * 20)
|
||||
const _Cgo_add_val = (3 + 5)
|
||||
|
||||
Vendored
+46
-46
@@ -14,16 +14,16 @@
|
||||
// testdata/errors.go:3:1: function "unusedFunction" in #cgo noescape line is not used
|
||||
|
||||
// Type checking errors after CGo processing:
|
||||
// testdata/errors.go:102: cannot use 2 << 10 (untyped int constant 2048) as C.char value in variable declaration (overflows)
|
||||
// testdata/errors.go:102: cannot use 2 << 10 (untyped int constant 2048) as _Cgo_char value in variable declaration (overflows)
|
||||
// testdata/errors.go:105: unknown field z in struct literal
|
||||
// testdata/errors.go:108: undefined: C.SOME_CONST_1
|
||||
// testdata/errors.go:110: cannot use C.SOME_CONST_3 (untyped int constant 1234) as byte value in variable declaration (overflows)
|
||||
// testdata/errors.go:112: undefined: C.SOME_CONST_4
|
||||
// testdata/errors.go:114: undefined: C.SOME_CONST_b
|
||||
// testdata/errors.go:116: undefined: C.SOME_CONST_startspace
|
||||
// testdata/errors.go:119: undefined: C.SOME_PARAM_CONST_invalid
|
||||
// testdata/errors.go:122: undefined: C.add_toomuch
|
||||
// testdata/errors.go:123: undefined: C.add_toolittle
|
||||
// testdata/errors.go:108: undefined: _Cgo_SOME_CONST_1
|
||||
// testdata/errors.go:110: cannot use _Cgo_SOME_CONST_3 (untyped int constant 1234) as byte value in variable declaration (overflows)
|
||||
// testdata/errors.go:112: undefined: _Cgo_SOME_CONST_4
|
||||
// testdata/errors.go:114: undefined: _Cgo_SOME_CONST_b
|
||||
// testdata/errors.go:116: undefined: _Cgo_SOME_CONST_startspace
|
||||
// testdata/errors.go:119: undefined: _Cgo_SOME_PARAM_CONST_invalid
|
||||
// testdata/errors.go:122: undefined: _Cgo_add_toomuch
|
||||
// testdata/errors.go:123: undefined: _Cgo_add_toolittle
|
||||
|
||||
package main
|
||||
|
||||
@@ -32,58 +32,58 @@ import "unsafe"
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
//go:linkname C.CString runtime.cgo_CString
|
||||
func C.CString(string) *C.char
|
||||
//go:linkname _Cgo_CString runtime.cgo_CString
|
||||
func _Cgo_CString(string) *_Cgo_char
|
||||
|
||||
//go:linkname C.GoString runtime.cgo_GoString
|
||||
func C.GoString(*C.char) string
|
||||
//go:linkname _Cgo_GoString runtime.cgo_GoString
|
||||
func _Cgo_GoString(*_Cgo_char) string
|
||||
|
||||
//go:linkname C.__GoStringN runtime.cgo_GoStringN
|
||||
func C.__GoStringN(*C.char, uintptr) string
|
||||
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN
|
||||
func _Cgo___GoStringN(*_Cgo_char, uintptr) string
|
||||
|
||||
func C.GoStringN(cstr *C.char, length C.int) string {
|
||||
return C.__GoStringN(cstr, uintptr(length))
|
||||
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string {
|
||||
return _Cgo___GoStringN(cstr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__GoBytes runtime.cgo_GoBytes
|
||||
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes
|
||||
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
|
||||
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
return C.__GoBytes(ptr, uintptr(length))
|
||||
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte {
|
||||
return _Cgo___GoBytes(ptr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__CBytes runtime.cgo_CBytes
|
||||
func C.__CBytes([]byte) unsafe.Pointer
|
||||
//go:linkname _Cgo___CBytes runtime.cgo_CBytes
|
||||
func _Cgo___CBytes([]byte) unsafe.Pointer
|
||||
|
||||
func C.CBytes(b []byte) unsafe.Pointer {
|
||||
return C.__CBytes(b)
|
||||
func _Cgo_CBytes(b []byte) unsafe.Pointer {
|
||||
return _Cgo___CBytes(b)
|
||||
}
|
||||
|
||||
//go:linkname C.__get_errno_num runtime.cgo_errno
|
||||
func C.__get_errno_num() uintptr
|
||||
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
|
||||
func _Cgo___get_errno_num() uintptr
|
||||
|
||||
func C.__get_errno() error {
|
||||
return syscall.Errno(C.__get_errno_num())
|
||||
func _Cgo___get_errno() error {
|
||||
return syscall.Errno(_Cgo___get_errno_num())
|
||||
}
|
||||
|
||||
type (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
C.uchar uint8
|
||||
C.short int16
|
||||
C.ushort uint16
|
||||
C.int int32
|
||||
C.uint uint32
|
||||
C.long int32
|
||||
C.ulong uint32
|
||||
C.longlong int64
|
||||
C.ulonglong uint64
|
||||
_Cgo_char uint8
|
||||
_Cgo_schar int8
|
||||
_Cgo_uchar uint8
|
||||
_Cgo_short int16
|
||||
_Cgo_ushort uint16
|
||||
_Cgo_int int32
|
||||
_Cgo_uint uint32
|
||||
_Cgo_long int32
|
||||
_Cgo_ulong uint32
|
||||
_Cgo_longlong int64
|
||||
_Cgo_ulonglong uint64
|
||||
)
|
||||
type C.struct_point_t struct {
|
||||
x C.int
|
||||
y C.int
|
||||
type _Cgo_struct_point_t struct {
|
||||
x _Cgo_int
|
||||
y _Cgo_int
|
||||
}
|
||||
type C.point_t = C.struct_point_t
|
||||
type _Cgo_point_t = _Cgo_struct_point_t
|
||||
|
||||
const C.SOME_CONST_3 = 1234
|
||||
const C.SOME_PARAM_CONST_valid = 3 + 4
|
||||
const _Cgo_SOME_CONST_3 = 1234
|
||||
const _Cgo_SOME_PARAM_CONST_valid = 3 + 4
|
||||
|
||||
Vendored
+33
-33
@@ -10,53 +10,53 @@ import "unsafe"
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
//go:linkname C.CString runtime.cgo_CString
|
||||
func C.CString(string) *C.char
|
||||
//go:linkname _Cgo_CString runtime.cgo_CString
|
||||
func _Cgo_CString(string) *_Cgo_char
|
||||
|
||||
//go:linkname C.GoString runtime.cgo_GoString
|
||||
func C.GoString(*C.char) string
|
||||
//go:linkname _Cgo_GoString runtime.cgo_GoString
|
||||
func _Cgo_GoString(*_Cgo_char) string
|
||||
|
||||
//go:linkname C.__GoStringN runtime.cgo_GoStringN
|
||||
func C.__GoStringN(*C.char, uintptr) string
|
||||
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN
|
||||
func _Cgo___GoStringN(*_Cgo_char, uintptr) string
|
||||
|
||||
func C.GoStringN(cstr *C.char, length C.int) string {
|
||||
return C.__GoStringN(cstr, uintptr(length))
|
||||
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string {
|
||||
return _Cgo___GoStringN(cstr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__GoBytes runtime.cgo_GoBytes
|
||||
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes
|
||||
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
|
||||
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
return C.__GoBytes(ptr, uintptr(length))
|
||||
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte {
|
||||
return _Cgo___GoBytes(ptr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__CBytes runtime.cgo_CBytes
|
||||
func C.__CBytes([]byte) unsafe.Pointer
|
||||
//go:linkname _Cgo___CBytes runtime.cgo_CBytes
|
||||
func _Cgo___CBytes([]byte) unsafe.Pointer
|
||||
|
||||
func C.CBytes(b []byte) unsafe.Pointer {
|
||||
return C.__CBytes(b)
|
||||
func _Cgo_CBytes(b []byte) unsafe.Pointer {
|
||||
return _Cgo___CBytes(b)
|
||||
}
|
||||
|
||||
//go:linkname C.__get_errno_num runtime.cgo_errno
|
||||
func C.__get_errno_num() uintptr
|
||||
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
|
||||
func _Cgo___get_errno_num() uintptr
|
||||
|
||||
func C.__get_errno() error {
|
||||
return syscall.Errno(C.__get_errno_num())
|
||||
func _Cgo___get_errno() error {
|
||||
return syscall.Errno(_Cgo___get_errno_num())
|
||||
}
|
||||
|
||||
type (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
C.uchar uint8
|
||||
C.short int16
|
||||
C.ushort uint16
|
||||
C.int int32
|
||||
C.uint uint32
|
||||
C.long int32
|
||||
C.ulong uint32
|
||||
C.longlong int64
|
||||
C.ulonglong uint64
|
||||
_Cgo_char uint8
|
||||
_Cgo_schar int8
|
||||
_Cgo_uchar uint8
|
||||
_Cgo_short int16
|
||||
_Cgo_ushort uint16
|
||||
_Cgo_int int32
|
||||
_Cgo_uint uint32
|
||||
_Cgo_long int32
|
||||
_Cgo_ulong uint32
|
||||
_Cgo_longlong int64
|
||||
_Cgo_ulonglong uint64
|
||||
)
|
||||
|
||||
const C.BAR = 3
|
||||
const C.FOO_H = 1
|
||||
const _Cgo_BAR = 3
|
||||
const _Cgo_FOO_H = 1
|
||||
|
||||
Vendored
+42
-42
@@ -5,80 +5,80 @@ import "unsafe"
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
//go:linkname C.CString runtime.cgo_CString
|
||||
func C.CString(string) *C.char
|
||||
//go:linkname _Cgo_CString runtime.cgo_CString
|
||||
func _Cgo_CString(string) *_Cgo_char
|
||||
|
||||
//go:linkname C.GoString runtime.cgo_GoString
|
||||
func C.GoString(*C.char) string
|
||||
//go:linkname _Cgo_GoString runtime.cgo_GoString
|
||||
func _Cgo_GoString(*_Cgo_char) string
|
||||
|
||||
//go:linkname C.__GoStringN runtime.cgo_GoStringN
|
||||
func C.__GoStringN(*C.char, uintptr) string
|
||||
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN
|
||||
func _Cgo___GoStringN(*_Cgo_char, uintptr) string
|
||||
|
||||
func C.GoStringN(cstr *C.char, length C.int) string {
|
||||
return C.__GoStringN(cstr, uintptr(length))
|
||||
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string {
|
||||
return _Cgo___GoStringN(cstr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__GoBytes runtime.cgo_GoBytes
|
||||
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes
|
||||
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
|
||||
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
return C.__GoBytes(ptr, uintptr(length))
|
||||
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte {
|
||||
return _Cgo___GoBytes(ptr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__CBytes runtime.cgo_CBytes
|
||||
func C.__CBytes([]byte) unsafe.Pointer
|
||||
//go:linkname _Cgo___CBytes runtime.cgo_CBytes
|
||||
func _Cgo___CBytes([]byte) unsafe.Pointer
|
||||
|
||||
func C.CBytes(b []byte) unsafe.Pointer {
|
||||
return C.__CBytes(b)
|
||||
func _Cgo_CBytes(b []byte) unsafe.Pointer {
|
||||
return _Cgo___CBytes(b)
|
||||
}
|
||||
|
||||
//go:linkname C.__get_errno_num runtime.cgo_errno
|
||||
func C.__get_errno_num() uintptr
|
||||
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
|
||||
func _Cgo___get_errno_num() uintptr
|
||||
|
||||
func C.__get_errno() error {
|
||||
return syscall.Errno(C.__get_errno_num())
|
||||
func _Cgo___get_errno() error {
|
||||
return syscall.Errno(_Cgo___get_errno_num())
|
||||
}
|
||||
|
||||
type (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
C.uchar uint8
|
||||
C.short int16
|
||||
C.ushort uint16
|
||||
C.int int32
|
||||
C.uint uint32
|
||||
C.long int32
|
||||
C.ulong uint32
|
||||
C.longlong int64
|
||||
C.ulonglong uint64
|
||||
_Cgo_char uint8
|
||||
_Cgo_schar int8
|
||||
_Cgo_uchar uint8
|
||||
_Cgo_short int16
|
||||
_Cgo_ushort uint16
|
||||
_Cgo_int int32
|
||||
_Cgo_uint uint32
|
||||
_Cgo_long int32
|
||||
_Cgo_ulong uint32
|
||||
_Cgo_longlong int64
|
||||
_Cgo_ulonglong uint64
|
||||
)
|
||||
|
||||
//export foo
|
||||
func C.foo(a C.int, b C.int) C.int
|
||||
func _Cgo_foo(a _Cgo_int, b _Cgo_int) _Cgo_int
|
||||
|
||||
var C.foo$funcaddr unsafe.Pointer
|
||||
var _Cgo_foo$funcaddr unsafe.Pointer
|
||||
|
||||
//export variadic0
|
||||
//go:variadic
|
||||
func C.variadic0()
|
||||
func _Cgo_variadic0()
|
||||
|
||||
var C.variadic0$funcaddr unsafe.Pointer
|
||||
var _Cgo_variadic0$funcaddr unsafe.Pointer
|
||||
|
||||
//export variadic2
|
||||
//go:variadic
|
||||
func C.variadic2(x C.int, y C.int)
|
||||
func _Cgo_variadic2(x _Cgo_int, y _Cgo_int)
|
||||
|
||||
var C.variadic2$funcaddr unsafe.Pointer
|
||||
var _Cgo_variadic2$funcaddr unsafe.Pointer
|
||||
|
||||
//export _Cgo_static_173c95a79b6df1980521_staticfunc
|
||||
func C.staticfunc!symbols.go(x C.int)
|
||||
func _Cgo_staticfunc!symbols.go(x _Cgo_int)
|
||||
|
||||
var C.staticfunc!symbols.go$funcaddr unsafe.Pointer
|
||||
var _Cgo_staticfunc!symbols.go$funcaddr unsafe.Pointer
|
||||
|
||||
//export notEscapingFunction
|
||||
//go:noescape
|
||||
func C.notEscapingFunction(a *C.int)
|
||||
func _Cgo_notEscapingFunction(a *_Cgo_int)
|
||||
|
||||
var C.notEscapingFunction$funcaddr unsafe.Pointer
|
||||
var _Cgo_notEscapingFunction$funcaddr unsafe.Pointer
|
||||
//go:extern someValue
|
||||
var C.someValue C.int
|
||||
var _Cgo_someValue _Cgo_int
|
||||
|
||||
Vendored
+103
-99
@@ -5,158 +5,162 @@ import "unsafe"
|
||||
|
||||
var _ unsafe.Pointer
|
||||
|
||||
//go:linkname C.CString runtime.cgo_CString
|
||||
func C.CString(string) *C.char
|
||||
//go:linkname _Cgo_CString runtime.cgo_CString
|
||||
func _Cgo_CString(string) *_Cgo_char
|
||||
|
||||
//go:linkname C.GoString runtime.cgo_GoString
|
||||
func C.GoString(*C.char) string
|
||||
//go:linkname _Cgo_GoString runtime.cgo_GoString
|
||||
func _Cgo_GoString(*_Cgo_char) string
|
||||
|
||||
//go:linkname C.__GoStringN runtime.cgo_GoStringN
|
||||
func C.__GoStringN(*C.char, uintptr) string
|
||||
//go:linkname _Cgo___GoStringN runtime.cgo_GoStringN
|
||||
func _Cgo___GoStringN(*_Cgo_char, uintptr) string
|
||||
|
||||
func C.GoStringN(cstr *C.char, length C.int) string {
|
||||
return C.__GoStringN(cstr, uintptr(length))
|
||||
func _Cgo_GoStringN(cstr *_Cgo_char, length _Cgo_int) string {
|
||||
return _Cgo___GoStringN(cstr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__GoBytes runtime.cgo_GoBytes
|
||||
func C.__GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
//go:linkname _Cgo___GoBytes runtime.cgo_GoBytes
|
||||
func _Cgo___GoBytes(unsafe.Pointer, uintptr) []byte
|
||||
|
||||
func C.GoBytes(ptr unsafe.Pointer, length C.int) []byte {
|
||||
return C.__GoBytes(ptr, uintptr(length))
|
||||
func _Cgo_GoBytes(ptr unsafe.Pointer, length _Cgo_int) []byte {
|
||||
return _Cgo___GoBytes(ptr, uintptr(length))
|
||||
}
|
||||
|
||||
//go:linkname C.__CBytes runtime.cgo_CBytes
|
||||
func C.__CBytes([]byte) unsafe.Pointer
|
||||
//go:linkname _Cgo___CBytes runtime.cgo_CBytes
|
||||
func _Cgo___CBytes([]byte) unsafe.Pointer
|
||||
|
||||
func C.CBytes(b []byte) unsafe.Pointer {
|
||||
return C.__CBytes(b)
|
||||
func _Cgo_CBytes(b []byte) unsafe.Pointer {
|
||||
return _Cgo___CBytes(b)
|
||||
}
|
||||
|
||||
//go:linkname C.__get_errno_num runtime.cgo_errno
|
||||
func C.__get_errno_num() uintptr
|
||||
//go:linkname _Cgo___get_errno_num runtime.cgo_errno
|
||||
func _Cgo___get_errno_num() uintptr
|
||||
|
||||
func C.__get_errno() error {
|
||||
return syscall.Errno(C.__get_errno_num())
|
||||
func _Cgo___get_errno() error {
|
||||
return syscall.Errno(_Cgo___get_errno_num())
|
||||
}
|
||||
|
||||
type (
|
||||
C.char uint8
|
||||
C.schar int8
|
||||
C.uchar uint8
|
||||
C.short int16
|
||||
C.ushort uint16
|
||||
C.int int32
|
||||
C.uint uint32
|
||||
C.long int32
|
||||
C.ulong uint32
|
||||
C.longlong int64
|
||||
C.ulonglong uint64
|
||||
_Cgo_char uint8
|
||||
_Cgo_schar int8
|
||||
_Cgo_uchar uint8
|
||||
_Cgo_short int16
|
||||
_Cgo_ushort uint16
|
||||
_Cgo_int int32
|
||||
_Cgo_uint uint32
|
||||
_Cgo_long int32
|
||||
_Cgo_ulong uint32
|
||||
_Cgo_longlong int64
|
||||
_Cgo_ulonglong uint64
|
||||
)
|
||||
type C.myint = C.int
|
||||
type C.struct_point2d_t struct {
|
||||
x C.int
|
||||
y C.int
|
||||
type _Cgo_myint = _Cgo_int
|
||||
type _Cgo_struct_point2d_t struct {
|
||||
x _Cgo_int
|
||||
y _Cgo_int
|
||||
}
|
||||
type C.point2d_t = C.struct_point2d_t
|
||||
type C.struct_point3d struct {
|
||||
x C.int
|
||||
y C.int
|
||||
z C.int
|
||||
type _Cgo_point2d_t = _Cgo_struct_point2d_t
|
||||
type _Cgo_struct_point3d struct {
|
||||
x _Cgo_int
|
||||
y _Cgo_int
|
||||
z _Cgo_int
|
||||
}
|
||||
type C.point3d_t = C.struct_point3d
|
||||
type C.struct_type1 struct {
|
||||
_type C.int
|
||||
__type C.int
|
||||
___type C.int
|
||||
type _Cgo_point3d_t = _Cgo_struct_point3d
|
||||
type _Cgo_struct_type1 struct {
|
||||
_type _Cgo_int
|
||||
__type _Cgo_int
|
||||
___type _Cgo_int
|
||||
}
|
||||
type C.struct_type2 struct{ _type C.int }
|
||||
type C.union_union1_t struct{ i C.int }
|
||||
type C.union1_t = C.union_union1_t
|
||||
type C.union_union3_t struct{ $union uint64 }
|
||||
type _Cgo_struct_type2 struct{ _type _Cgo_int }
|
||||
type _Cgo_union_union1_t struct{ i _Cgo_int }
|
||||
type _Cgo_union1_t = _Cgo_union_union1_t
|
||||
type _Cgo_union_union3_t struct{ $union uint64 }
|
||||
|
||||
func (union *C.union_union3_t) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
|
||||
func (union *C.union_union3_t) unionfield_d() *float64 {
|
||||
func (union *_Cgo_union_union3_t) unionfield_i() *_Cgo_int {
|
||||
return (*_Cgo_int)(unsafe.Pointer(&union.$union))
|
||||
}
|
||||
func (union *_Cgo_union_union3_t) unionfield_d() *float64 {
|
||||
return (*float64)(unsafe.Pointer(&union.$union))
|
||||
}
|
||||
func (union *C.union_union3_t) unionfield_s() *C.short {
|
||||
return (*C.short)(unsafe.Pointer(&union.$union))
|
||||
func (union *_Cgo_union_union3_t) unionfield_s() *_Cgo_short {
|
||||
return (*_Cgo_short)(unsafe.Pointer(&union.$union))
|
||||
}
|
||||
|
||||
type C.union3_t = C.union_union3_t
|
||||
type C.union_union2d struct{ $union [2]uint64 }
|
||||
type _Cgo_union3_t = _Cgo_union_union3_t
|
||||
type _Cgo_union_union2d struct{ $union [2]uint64 }
|
||||
|
||||
func (union *C.union_union2d) unionfield_i() *C.int { return (*C.int)(unsafe.Pointer(&union.$union)) }
|
||||
func (union *C.union_union2d) unionfield_d() *[2]float64 {
|
||||
func (union *_Cgo_union_union2d) unionfield_i() *_Cgo_int {
|
||||
return (*_Cgo_int)(unsafe.Pointer(&union.$union))
|
||||
}
|
||||
func (union *_Cgo_union_union2d) unionfield_d() *[2]float64 {
|
||||
return (*[2]float64)(unsafe.Pointer(&union.$union))
|
||||
}
|
||||
|
||||
type C.union2d_t = C.union_union2d
|
||||
type C.union_unionarray_t struct{ arr [10]C.uchar }
|
||||
type C.unionarray_t = C.union_unionarray_t
|
||||
type C._Ctype_union___0 struct{ $union [3]uint32 }
|
||||
type _Cgo_union2d_t = _Cgo_union_union2d
|
||||
type _Cgo_union_unionarray_t struct{ arr [10]_Cgo_uchar }
|
||||
type _Cgo_unionarray_t = _Cgo_union_unionarray_t
|
||||
type _Cgo__Ctype_union___0 struct{ $union [3]uint32 }
|
||||
|
||||
func (union *C._Ctype_union___0) unionfield_area() *C.point2d_t {
|
||||
return (*C.point2d_t)(unsafe.Pointer(&union.$union))
|
||||
func (union *_Cgo__Ctype_union___0) unionfield_area() *_Cgo_point2d_t {
|
||||
return (*_Cgo_point2d_t)(unsafe.Pointer(&union.$union))
|
||||
}
|
||||
func (union *C._Ctype_union___0) unionfield_solid() *C.point3d_t {
|
||||
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
|
||||
func (union *_Cgo__Ctype_union___0) unionfield_solid() *_Cgo_point3d_t {
|
||||
return (*_Cgo_point3d_t)(unsafe.Pointer(&union.$union))
|
||||
}
|
||||
|
||||
type C.struct_struct_nested_t struct {
|
||||
begin C.point2d_t
|
||||
end C.point2d_t
|
||||
tag C.int
|
||||
type _Cgo_struct_struct_nested_t struct {
|
||||
begin _Cgo_point2d_t
|
||||
end _Cgo_point2d_t
|
||||
tag _Cgo_int
|
||||
|
||||
coord C._Ctype_union___0
|
||||
coord _Cgo__Ctype_union___0
|
||||
}
|
||||
type C.struct_nested_t = C.struct_struct_nested_t
|
||||
type C.union_union_nested_t struct{ $union [2]uint64 }
|
||||
type _Cgo_struct_nested_t = _Cgo_struct_struct_nested_t
|
||||
type _Cgo_union_union_nested_t struct{ $union [2]uint64 }
|
||||
|
||||
func (union *C.union_union_nested_t) unionfield_point() *C.point3d_t {
|
||||
return (*C.point3d_t)(unsafe.Pointer(&union.$union))
|
||||
func (union *_Cgo_union_union_nested_t) unionfield_point() *_Cgo_point3d_t {
|
||||
return (*_Cgo_point3d_t)(unsafe.Pointer(&union.$union))
|
||||
}
|
||||
func (union *C.union_union_nested_t) unionfield_array() *C.unionarray_t {
|
||||
return (*C.unionarray_t)(unsafe.Pointer(&union.$union))
|
||||
func (union *_Cgo_union_union_nested_t) unionfield_array() *_Cgo_unionarray_t {
|
||||
return (*_Cgo_unionarray_t)(unsafe.Pointer(&union.$union))
|
||||
}
|
||||
func (union *C.union_union_nested_t) unionfield_thing() *C.union3_t {
|
||||
return (*C.union3_t)(unsafe.Pointer(&union.$union))
|
||||
func (union *_Cgo_union_union_nested_t) unionfield_thing() *_Cgo_union3_t {
|
||||
return (*_Cgo_union3_t)(unsafe.Pointer(&union.$union))
|
||||
}
|
||||
|
||||
type C.union_nested_t = C.union_union_nested_t
|
||||
type C.enum_option = C.int
|
||||
type C.option_t = C.enum_option
|
||||
type C.enum_option2_t = C.uint
|
||||
type C.option2_t = C.enum_option2_t
|
||||
type C.struct_types_t struct {
|
||||
type _Cgo_union_nested_t = _Cgo_union_union_nested_t
|
||||
type _Cgo_enum_option = _Cgo_int
|
||||
type _Cgo_option_t = _Cgo_enum_option
|
||||
type _Cgo_enum_option2_t = _Cgo_uint
|
||||
type _Cgo_option2_t = _Cgo_enum_option2_t
|
||||
type _Cgo_struct_types_t struct {
|
||||
f float32
|
||||
d float64
|
||||
ptr *C.int
|
||||
ptr *_Cgo_int
|
||||
}
|
||||
type C.types_t = C.struct_types_t
|
||||
type C.myIntArray = [10]C.int
|
||||
type C.struct_bitfield_t struct {
|
||||
start C.uchar
|
||||
__bitfield_1 C.uchar
|
||||
type _Cgo_types_t = _Cgo_struct_types_t
|
||||
type _Cgo_myIntArray = [10]_Cgo_int
|
||||
type _Cgo_struct_bitfield_t struct {
|
||||
start _Cgo_uchar
|
||||
__bitfield_1 _Cgo_uchar
|
||||
|
||||
d C.uchar
|
||||
e C.uchar
|
||||
d _Cgo_uchar
|
||||
e _Cgo_uchar
|
||||
}
|
||||
|
||||
func (s *C.struct_bitfield_t) bitfield_a() C.uchar { return s.__bitfield_1 & 0x1f }
|
||||
func (s *C.struct_bitfield_t) set_bitfield_a(value C.uchar) {
|
||||
func (s *_Cgo_struct_bitfield_t) bitfield_a() _Cgo_uchar { return s.__bitfield_1 & 0x1f }
|
||||
func (s *_Cgo_struct_bitfield_t) set_bitfield_a(value _Cgo_uchar) {
|
||||
s.__bitfield_1 = s.__bitfield_1&^0x1f | value&0x1f<<0
|
||||
}
|
||||
func (s *C.struct_bitfield_t) bitfield_b() C.uchar {
|
||||
func (s *_Cgo_struct_bitfield_t) bitfield_b() _Cgo_uchar {
|
||||
return s.__bitfield_1 >> 5 & 0x1
|
||||
}
|
||||
func (s *C.struct_bitfield_t) set_bitfield_b(value C.uchar) {
|
||||
func (s *_Cgo_struct_bitfield_t) set_bitfield_b(value _Cgo_uchar) {
|
||||
s.__bitfield_1 = s.__bitfield_1&^0x20 | value&0x1<<5
|
||||
}
|
||||
func (s *C.struct_bitfield_t) bitfield_c() C.uchar {
|
||||
func (s *_Cgo_struct_bitfield_t) bitfield_c() _Cgo_uchar {
|
||||
return s.__bitfield_1 >> 6
|
||||
}
|
||||
func (s *C.struct_bitfield_t) set_bitfield_c(value C.uchar,
|
||||
func (s *_Cgo_struct_bitfield_t) set_bitfield_c(value _Cgo_uchar,
|
||||
|
||||
) { s.__bitfield_1 = s.__bitfield_1&0x3f | value<<6 }
|
||||
|
||||
type C.bitfield_t = C.struct_bitfield_t
|
||||
type _Cgo_bitfield_t = _Cgo_struct_bitfield_t
|
||||
|
||||
@@ -99,11 +99,6 @@ func (c *Config) BuildTags() []string {
|
||||
"math_big_pure_go", // to get math/big to work
|
||||
"gc." + c.GC(), "scheduler." + c.Scheduler(), // used inside the runtime package
|
||||
"serial." + c.Serial()}...) // used inside the machine package
|
||||
switch c.Scheduler() {
|
||||
case "threads", "cores":
|
||||
default:
|
||||
tags = append(tags, "tinygo.unicore")
|
||||
}
|
||||
for i := 1; i <= c.GoMinorVersion; i++ {
|
||||
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
validBuildModeOptions = []string{"default", "c-shared"}
|
||||
validBuildModeOptions = []string{"default", "c-shared", "wasi-legacy"}
|
||||
validGCOptions = []string{"none", "leaking", "conservative", "custom", "precise"}
|
||||
validSchedulerOptions = []string{"none", "tasks", "asyncify", "threads", "cores"}
|
||||
validSchedulerOptions = []string{"none", "tasks", "asyncify"}
|
||||
validSerialOptions = []string{"none", "uart", "usb", "rtt"}
|
||||
validPrintSizeOptions = []string{"none", "short", "full", "html"}
|
||||
validPanicStrategyOptions = []string{"print", "trap"}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
func TestVerifyOptions(t *testing.T) {
|
||||
|
||||
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, conservative, custom, precise`)
|
||||
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify, threads`)
|
||||
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, asyncify`)
|
||||
expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full, html`)
|
||||
expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`)
|
||||
|
||||
|
||||
+4
-33
@@ -248,6 +248,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
GOARCH: options.GOARCH,
|
||||
BuildTags: []string{options.GOOS, options.GOARCH},
|
||||
GC: "precise",
|
||||
Scheduler: "tasks",
|
||||
Linker: "cc",
|
||||
DefaultStackSize: 1024 * 64, // 64kB
|
||||
GDB: []string{"gdb"},
|
||||
@@ -355,17 +356,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
return nil, fmt.Errorf("invalid GOMIPS=%s: must be hardfloat or softfloat", options.GOMIPS)
|
||||
}
|
||||
case "wasm":
|
||||
llvmarch = "wasm32"
|
||||
spec.CPU = "generic"
|
||||
spec.Features = "+bulk-memory,+mutable-globals,+nontrapping-fptoint,+sign-ext,-multivalue,-reference-types"
|
||||
spec.BuildTags = append(spec.BuildTags, "tinygo.wasm")
|
||||
spec.CFlags = append(spec.CFlags,
|
||||
"-mbulk-memory",
|
||||
"-mnontrapping-fptoint",
|
||||
"-mno-multivalue",
|
||||
"-mno-reference-types",
|
||||
"-msign-ext",
|
||||
)
|
||||
return nil, fmt.Errorf("GOARCH=wasm but GOOS is unset. Please set GOOS to wasm, wasip1, or wasip2.")
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown GOARCH=%s", options.GOARCH)
|
||||
}
|
||||
@@ -380,7 +371,6 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
platformVersion = "11.0.0" // first macosx platform with arm64 support
|
||||
}
|
||||
llvmvendor = "apple"
|
||||
spec.Scheduler = "tasks"
|
||||
spec.Linker = "ld.lld"
|
||||
spec.Libc = "darwin-libSystem"
|
||||
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer to
|
||||
@@ -398,7 +388,6 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
"src/runtime/runtime_unix.c",
|
||||
"src/runtime/signal.c")
|
||||
case "linux":
|
||||
spec.Scheduler = "threads"
|
||||
spec.Linker = "ld.lld"
|
||||
spec.RTLib = "compiler-rt"
|
||||
spec.Libc = "musl"
|
||||
@@ -419,11 +408,9 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
}
|
||||
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||
"src/internal/futex/futex_linux.c",
|
||||
"src/internal/task/task_threads.c",
|
||||
"src/runtime/runtime_unix.c",
|
||||
"src/runtime/signal.c")
|
||||
case "windows":
|
||||
spec.Scheduler = "tasks"
|
||||
spec.Linker = "ld.lld"
|
||||
spec.Libc = "mingw-w64"
|
||||
// Note: using a medium code model, low image base and no ASLR
|
||||
@@ -449,23 +436,8 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
"--no-insert-timestamp",
|
||||
"--no-dynamicbase",
|
||||
)
|
||||
case "wasip1":
|
||||
spec.GC = "" // use default GC
|
||||
spec.Scheduler = "asyncify"
|
||||
spec.Linker = "wasm-ld"
|
||||
spec.RTLib = "compiler-rt"
|
||||
spec.Libc = "wasi-libc"
|
||||
spec.DefaultStackSize = 1024 * 64 // 64kB
|
||||
spec.LDFlags = append(spec.LDFlags,
|
||||
"--stack-first",
|
||||
"--no-demangle",
|
||||
)
|
||||
spec.Emulator = "wasmtime run --dir={tmpDir}::/tmp {}"
|
||||
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||
"src/runtime/asm_tinygowasm.S",
|
||||
"src/internal/task/task_asyncify_wasm.S",
|
||||
)
|
||||
llvmos = "wasi"
|
||||
case "wasm", "wasip1", "wasip2":
|
||||
return nil, fmt.Errorf("GOOS=%s but GOARCH is unset. Please set GOARCH to wasm", options.GOOS)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown GOOS=%s", options.GOOS)
|
||||
}
|
||||
@@ -501,7 +473,6 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
}
|
||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/asm_"+asmGoarch+suffix+".S")
|
||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_stack_"+asmGoarch+suffix+".S")
|
||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_cores.c")
|
||||
}
|
||||
|
||||
// Configure the emulator.
|
||||
|
||||
+6
-5
@@ -18,11 +18,12 @@ var stdlibAliases = map[string]string{
|
||||
// crypto packages
|
||||
"crypto/ed25519/internal/edwards25519/field.feMul": "crypto/ed25519/internal/edwards25519/field.feMulGeneric",
|
||||
"crypto/internal/edwards25519/field.feSquare": "crypto/ed25519/internal/edwards25519/field.feSquareGeneric",
|
||||
"crypto/md5.block": "crypto/md5.blockGeneric",
|
||||
"crypto/sha1.block": "crypto/sha1.blockGeneric",
|
||||
"crypto/sha1.blockAMD64": "crypto/sha1.blockGeneric",
|
||||
"crypto/sha256.block": "crypto/sha256.blockGeneric",
|
||||
"crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric",
|
||||
"crypto/md5.block": "crypto/md5.blockGeneric",
|
||||
"crypto/sha1.block": "crypto/sha1.blockGeneric",
|
||||
"crypto/sha1.blockAMD64": "crypto/sha1.blockGeneric",
|
||||
"crypto/sha256.block": "crypto/sha256.blockGeneric",
|
||||
"crypto/sha512.blockAMD64": "crypto/sha512.blockGeneric",
|
||||
"internal/chacha8rand.block": "internal/chacha8rand.block_generic",
|
||||
|
||||
// AES
|
||||
"crypto/aes.decryptBlockAsm": "crypto/aes.decryptBlock",
|
||||
|
||||
+8
-6
@@ -208,8 +208,6 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
// > circumstances, and should not be exposed to source languages.
|
||||
llvmutil.AppendToGlobal(c.mod, "llvm.compiler.used", llvmFn)
|
||||
}
|
||||
case "tinygo_exitTask", "tinygo_schedulerUnlock":
|
||||
llvmutil.AppendToGlobal(c.mod, "llvm.used", llvmFn)
|
||||
}
|
||||
|
||||
// External/exported functions may not retain pointer values.
|
||||
@@ -285,6 +283,11 @@ func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
|
||||
info.wasmName = "_start"
|
||||
info.exported = true
|
||||
}
|
||||
if info.linkName == "runtime.wasmEntryLegacy" && c.BuildMode == "wasi-legacy" {
|
||||
info.linkName = "_start"
|
||||
info.wasmName = "_start"
|
||||
info.exported = true
|
||||
}
|
||||
|
||||
// Check for //go: pragmas, which may change the link name (among others).
|
||||
c.parsePragmas(&info, f)
|
||||
@@ -429,9 +432,8 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
// pass for C variadic functions. This includes both explicit
|
||||
// (with ...) and implicit (no parameters in signature)
|
||||
// functions.
|
||||
if strings.HasPrefix(f.Name(), "C.") {
|
||||
// This prefix cannot naturally be created, it must have
|
||||
// been created as a result of CGo preprocessing.
|
||||
if strings.HasPrefix(f.Name(), "_Cgo_") {
|
||||
// This prefix was created as a result of CGo preprocessing.
|
||||
info.variadic = true
|
||||
}
|
||||
}
|
||||
@@ -444,7 +446,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
// The list of allowed types is based on this proposal:
|
||||
// https://github.com/golang/go/issues/59149
|
||||
func (c *compilerContext) checkWasmImportExport(f *ssa.Function, pragma string) {
|
||||
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" || c.pkg.Path() == "syscall" {
|
||||
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" || c.pkg.Path() == "syscall" || c.pkg.Path() == "crypto/internal/sysrand" {
|
||||
// The runtime is a special case. Allow all kinds of parameters
|
||||
// (importantly, including pointers).
|
||||
return
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const version = "0.36.0-dev"
|
||||
const version = "0.36.0"
|
||||
|
||||
// Return TinyGo version, either in the form 0.30.0 or as a development version
|
||||
// (like 0.30.0-dev-abcd012).
|
||||
|
||||
@@ -970,9 +970,9 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me
|
||||
case llvm.Call:
|
||||
llvmFn := operands[len(operands)-1]
|
||||
args := operands[:len(operands)-1]
|
||||
for _, arg := range args {
|
||||
if arg.Type().TypeKind() == llvm.PointerTypeKind {
|
||||
err := mem.markExternalStore(arg)
|
||||
for _, op := range operands {
|
||||
if op.Type().TypeKind() == llvm.PointerTypeKind {
|
||||
err := mem.markExternalStore(op)
|
||||
if err != nil {
|
||||
return r.errorAt(inst, err)
|
||||
}
|
||||
|
||||
@@ -269,6 +269,8 @@ func pathsToOverride(goMinor int, needsSyscallPackage bool) map[string]bool {
|
||||
|
||||
if needsSyscallPackage {
|
||||
paths["syscall/"] = true // include syscall/js
|
||||
paths["internal/syscall/"] = true
|
||||
paths["internal/syscall/unix/"] = false
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
@@ -1501,7 +1501,7 @@ func main() {
|
||||
var tags buildutil.TagsFlag
|
||||
flag.Var(&tags, "tags", "a space-separated list of extra build tags")
|
||||
target := flag.String("target", "", "chip/board name or JSON target specification file")
|
||||
buildMode := flag.String("buildmode", "", "build mode to use (default, c-shared)")
|
||||
buildMode := flag.String("buildmode", "", "build mode to use (default, c-shared, wasi-legacy)")
|
||||
var stackSize uint64
|
||||
flag.Func("stack-size", "goroutine stack size (if unknown at compile time)", func(s string) error {
|
||||
size, err := bytesize.Parse(s)
|
||||
@@ -1684,8 +1684,24 @@ func main() {
|
||||
usage(command)
|
||||
os.Exit(1)
|
||||
}
|
||||
if options.Target == "" && filepath.Ext(outpath) == ".wasm" {
|
||||
options.Target = "wasm"
|
||||
if options.Target == "" {
|
||||
switch {
|
||||
case options.GOARCH == "wasm":
|
||||
switch options.GOOS {
|
||||
case "js":
|
||||
options.Target = "wasm"
|
||||
case "wasip1":
|
||||
options.Target = "wasip1"
|
||||
case "wasip2":
|
||||
options.Target = "wasip2"
|
||||
default:
|
||||
fmt.Fprintln(os.Stderr, "GOARCH=wasm but GOOS is not set correctly. Please set GOOS to wasm, wasip1, or wasip2.")
|
||||
os.Exit(1)
|
||||
}
|
||||
case filepath.Ext(outpath) == ".wasm":
|
||||
fmt.Fprintln(os.Stderr, "you appear to want to build a wasm file, but have not specified either a target flag, or the GOARCH/GOOS to use.")
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
err := Build(pkgName, outpath, options)
|
||||
|
||||
@@ -594,6 +594,15 @@ func TestWasmExport(t *testing.T) {
|
||||
noOutput: true, // wasm-unknown cannot produce output
|
||||
command: true,
|
||||
},
|
||||
// Test buildmode=wasi-legacy with WASI.
|
||||
{
|
||||
name: "WASIp1-legacy",
|
||||
target: "wasip1",
|
||||
buildMode: "wasi-legacy",
|
||||
scheduler: "none",
|
||||
file: "wasmexport-noscheduler.go",
|
||||
command: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey
|
||||
//go:build nrf || (stm32 && !(stm32f103 || stm32l0x1)) || (sam && atsamd51) || (sam && atsame5x) || esp32c3 || tkey || (tinygo.riscv32 && virt)
|
||||
|
||||
// If you update the above build constraint, you'll probably also need to update
|
||||
// src/runtime/rand_hwrng.go.
|
||||
|
||||
@@ -17,6 +17,37 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
VersionTLS10 = 0x0301
|
||||
VersionTLS11 = 0x0302
|
||||
VersionTLS12 = 0x0303
|
||||
VersionTLS13 = 0x0304
|
||||
|
||||
// Deprecated: SSLv3 is cryptographically broken, and is no longer
|
||||
// supported by this package. See golang.org/issue/32716.
|
||||
VersionSSL30 = 0x0300
|
||||
)
|
||||
|
||||
// VersionName returns the name for the provided TLS version number
|
||||
// (e.g. "TLS 1.3"), or a fallback representation of the value if the
|
||||
// version is not implemented by this package.
|
||||
func VersionName(version uint16) string {
|
||||
switch version {
|
||||
case VersionSSL30:
|
||||
return "SSLv3"
|
||||
case VersionTLS10:
|
||||
return "TLS 1.0"
|
||||
case VersionTLS11:
|
||||
return "TLS 1.1"
|
||||
case VersionTLS12:
|
||||
return "TLS 1.2"
|
||||
case VersionTLS13:
|
||||
return "TLS 1.3"
|
||||
default:
|
||||
return fmt.Sprintf("0x%04X", version)
|
||||
}
|
||||
}
|
||||
|
||||
// CurveID is the type of a TLS identifier for an elliptic curve. See
|
||||
// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8.
|
||||
//
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package abi
|
||||
|
||||
type Type struct {
|
||||
// Intentionally left empty. TinyGo uses a different way to represent types,
|
||||
// so this is unimplementable. The type definition here is purely for
|
||||
// compatibility.
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package unix
|
||||
|
||||
const (
|
||||
R_OK = 0x4
|
||||
W_OK = 0x2
|
||||
X_OK = 0x1
|
||||
)
|
||||
@@ -0,0 +1,10 @@
|
||||
package unix
|
||||
|
||||
import "syscall"
|
||||
|
||||
func Eaccess(path string, mode uint32) error {
|
||||
// We don't support this syscall on baremetal or wasm.
|
||||
// Callers are generally able to deal with this since unix.Eaccess also
|
||||
// isn't available on Android.
|
||||
return syscall.ENOSYS
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package unix
|
||||
|
||||
type GetRandomFlag uintptr
|
||||
|
||||
const (
|
||||
GRND_NONBLOCK GetRandomFlag = 0x0001
|
||||
GRND_RANDOM GetRandomFlag = 0x0002
|
||||
)
|
||||
|
||||
func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) {
|
||||
panic("todo: unix.GetRandom")
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
//go:build tinygo.unicore
|
||||
|
||||
package task
|
||||
|
||||
// Atomics implementation for cooperative systems. The atomic types here aren't
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
//go:build !tinygo.unicore
|
||||
|
||||
package task
|
||||
|
||||
// Atomics implementation for non-cooperative systems (multithreaded, etc).
|
||||
// These atomic types use real atomic instructions.
|
||||
|
||||
import "sync/atomic"
|
||||
|
||||
type (
|
||||
Uintptr = atomic.Uintptr
|
||||
Uint32 = atomic.Uint32
|
||||
Uint64 = atomic.Uint64
|
||||
)
|
||||
@@ -1,5 +1,3 @@
|
||||
//go:build tinygo.unicore
|
||||
|
||||
package task
|
||||
|
||||
// A futex is a way for userspace to wait with the pointer as the key, and for
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
//go:build scheduler.cores
|
||||
|
||||
package task
|
||||
|
||||
import "runtime/interrupt"
|
||||
|
||||
// A futex is a way for userspace to wait with the pointer as the key, and for
|
||||
// another thread to wake one or all waiting threads keyed on the same pointer.
|
||||
//
|
||||
// A futex does not change the underlying value, it only reads it before to prevent
|
||||
// lost wake-ups.
|
||||
type Futex struct {
|
||||
Uint32
|
||||
|
||||
waiters Stack
|
||||
}
|
||||
|
||||
// Atomically check for cmp to still be equal to the futex value and if so, go
|
||||
// to sleep. Return true if we were definitely awoken by a call to Wake or
|
||||
// WakeAll, and false if we can't be sure of that.
|
||||
func (f *Futex) Wait(cmp uint32) (awoken bool) {
|
||||
mask := futexLock()
|
||||
|
||||
if f.Uint32.Load() != cmp {
|
||||
futexUnlock(mask)
|
||||
return false
|
||||
}
|
||||
|
||||
// Push the current goroutine onto the waiter stack.
|
||||
f.waiters.Push(Current())
|
||||
|
||||
futexUnlock(mask)
|
||||
|
||||
// Pause until this task is awoken by Wake/WakeAll.
|
||||
Pause()
|
||||
|
||||
// We were awoken by a call to Wake or WakeAll. There is no chance for
|
||||
// spurious wakeups.
|
||||
return true
|
||||
}
|
||||
|
||||
// Wake a single waiter.
|
||||
func (f *Futex) Wake() {
|
||||
mask := futexLock()
|
||||
if t := f.waiters.Pop(); t != nil {
|
||||
scheduleTask(t)
|
||||
}
|
||||
futexUnlock(mask)
|
||||
}
|
||||
|
||||
// Wake all waiters.
|
||||
func (f *Futex) WakeAll() {
|
||||
mask := futexLock()
|
||||
for t := f.waiters.Pop(); t != nil; t = f.waiters.Pop() {
|
||||
scheduleTask(t)
|
||||
}
|
||||
futexUnlock(mask)
|
||||
}
|
||||
|
||||
//go:linkname futexLock runtime.futexLock
|
||||
func futexLock() interrupt.State
|
||||
|
||||
//go:linkname futexUnlock runtime.futexUnlock
|
||||
func futexUnlock(interrupt.State)
|
||||
@@ -1,7 +0,0 @@
|
||||
//go:build scheduler.threads
|
||||
|
||||
package task
|
||||
|
||||
import "internal/futex"
|
||||
|
||||
type Futex = futex.Futex
|
||||
@@ -1,9 +0,0 @@
|
||||
//go:build linux && !baremetal
|
||||
|
||||
package task
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// Musl uses a pointer (or unsigned long for C++) so unsafe.Pointer should be
|
||||
// fine.
|
||||
type threadID unsafe.Pointer
|
||||
@@ -1,5 +1,3 @@
|
||||
//go:build tinygo.unicore
|
||||
|
||||
package task
|
||||
|
||||
type Mutex struct {
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
//go:build !tinygo.unicore
|
||||
|
||||
package task
|
||||
|
||||
// Futex-based mutex.
|
||||
// This is largely based on the paper "Futexes are Tricky" by Ulrich Drepper.
|
||||
// It describes a few ways to implement mutexes using a futex, and how some
|
||||
// seemingly-obvious implementations don't exactly work as intended.
|
||||
// Unfortunately, Go atomic operations work slightly differently so we can't
|
||||
// copy the algorithm verbatim.
|
||||
//
|
||||
// The implementation works like this. The futex can have 3 different values,
|
||||
// depending on the state:
|
||||
//
|
||||
// - 0: the futex is currently unlocked.
|
||||
// - 1: the futex is locked, but is uncontended. There is one special case: if
|
||||
// a contended futex is unlocked, it is set to 0. It is possible for another
|
||||
// thread to lock the futex before the next waiter is woken. But because a
|
||||
// waiter will be woken (if there is one), it will always change to 2
|
||||
// regardless. So this is not a problem.
|
||||
// - 2: the futex is locked, and is contended. At least one thread is trying
|
||||
// to obtain the lock (and is in the contended loop, see below).
|
||||
//
|
||||
// For the paper, see:
|
||||
// https://dept-info.labri.fr/~denis/Enseignement/2008-IR/Articles/01-futex.pdf)
|
||||
|
||||
type Mutex struct {
|
||||
futex Futex
|
||||
}
|
||||
|
||||
func (m *Mutex) Lock() {
|
||||
// Fast path: try to take an uncontended lock.
|
||||
if m.futex.CompareAndSwap(0, 1) {
|
||||
// We obtained the mutex.
|
||||
return
|
||||
}
|
||||
|
||||
// The futex is contended, so we enter the contended loop.
|
||||
// If we manage to change the futex from 0 to 2, we managed to take the
|
||||
// lock. Else, we have to wait until a call to Unlock unlocks this mutex.
|
||||
// (Unlock will wake one waiter when it finds the futex is set to 2 when
|
||||
// unlocking).
|
||||
for m.futex.Swap(2) != 0 {
|
||||
// Wait until we get resumed in Unlock.
|
||||
m.futex.Wait(2)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Mutex) Unlock() {
|
||||
if old := m.futex.Swap(0); old == 0 {
|
||||
// Mutex wasn't locked before.
|
||||
panic("sync: unlock of unlocked Mutex")
|
||||
} else if old == 2 {
|
||||
// Mutex was a contended lock, so we need to wake the next waiter.
|
||||
m.futex.Wake()
|
||||
}
|
||||
}
|
||||
|
||||
// TryLock tries to lock m and reports whether it succeeded.
|
||||
//
|
||||
// Note that while correct uses of TryLock do exist, they are rare,
|
||||
// and use of TryLock is often a sign of a deeper problem
|
||||
// in a particular use of mutexes.
|
||||
func (m *Mutex) TryLock() bool {
|
||||
// Fast path: try to take an uncontended lock.
|
||||
if m.futex.CompareAndSwap(0, 1) {
|
||||
// We obtained the mutex.
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
//go:build tinygo.unicore
|
||||
|
||||
package task
|
||||
|
||||
// PMutex is a real mutex on systems that can be either preemptive or threaded,
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
//go:build !tinygo.unicore
|
||||
|
||||
package task
|
||||
|
||||
// PMutex is a real mutex on systems that can be either preemptive or threaded,
|
||||
// and a dummy lock on other (purely cooperative) systems.
|
||||
//
|
||||
// It is mainly useful for short operations that need a lock when threading may
|
||||
// be involved, but which do not need a lock with a purely cooperative
|
||||
// scheduler.
|
||||
type PMutex = Mutex
|
||||
@@ -1,32 +0,0 @@
|
||||
package task
|
||||
|
||||
// Barebones semaphore implementation.
|
||||
// The main limitation is that if there are multiple waiters, a single Post()
|
||||
// call won't do anything. Only when Post() has been called to awaken all
|
||||
// waiters will the waiters proceed.
|
||||
// This limitation is not a problem when there will only be a single waiter.
|
||||
type Semaphore struct {
|
||||
futex Futex
|
||||
}
|
||||
|
||||
// Post (unlock) the semaphore, incrementing the value in the semaphore.
|
||||
func (s *Semaphore) Post() {
|
||||
newValue := s.futex.Add(1)
|
||||
if newValue == 0 {
|
||||
s.futex.WakeAll()
|
||||
}
|
||||
}
|
||||
|
||||
// Wait (lock) the semaphore, decrementing the value in the semaphore.
|
||||
func (s *Semaphore) Wait() {
|
||||
delta := int32(-1)
|
||||
value := s.futex.Add(uint32(delta))
|
||||
for {
|
||||
if int32(value) >= 0 {
|
||||
// Semaphore unlocked!
|
||||
return
|
||||
}
|
||||
s.futex.Wait(value)
|
||||
value = s.futex.Load()
|
||||
}
|
||||
}
|
||||
@@ -21,19 +21,14 @@ type Task struct {
|
||||
// state is the underlying running state of the task.
|
||||
state state
|
||||
|
||||
RunState uint8
|
||||
// This is needed for some crypto packages.
|
||||
FipsIndicator uint8
|
||||
|
||||
// DeferFrame stores a pointer to the (stack allocated) defer frame of the
|
||||
// goroutine that is used for the recover builtin.
|
||||
DeferFrame unsafe.Pointer
|
||||
}
|
||||
|
||||
const (
|
||||
RunStatePaused = iota
|
||||
RunStateRunning
|
||||
RunStateResuming
|
||||
)
|
||||
|
||||
// DataUint32 returns the Data field as a uint32. The value is only valid after
|
||||
// setting it through SetDataUint32 or by storing to it using DataAtomicUint32.
|
||||
func (t *Task) DataUint32() uint32 {
|
||||
@@ -61,11 +56,3 @@ func runtime_alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer
|
||||
|
||||
//go:linkname scheduleTask runtime.scheduleTask
|
||||
func scheduleTask(*Task)
|
||||
|
||||
//go:linkname runtimePanic runtime.runtimePanic
|
||||
func runtimePanic(str string)
|
||||
|
||||
// Stack canary, to detect a stack overflow. The number is a random number
|
||||
// generated by random.org. The bit fiddling dance is necessary because
|
||||
// otherwise Go wouldn't allow the cast to a smaller integer size.
|
||||
const stackCanary = uintptr(uint64(0x670c1333b83bf575) & uint64(^uintptr(0)))
|
||||
|
||||
@@ -6,6 +6,14 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Stack canary, to detect a stack overflow. The number is a random number
|
||||
// generated by random.org. The bit fiddling dance is necessary because
|
||||
// otherwise Go wouldn't allow the cast to a smaller integer size.
|
||||
const stackCanary = uintptr(uint64(0x670c1333b83bf575) & uint64(^uintptr(0)))
|
||||
|
||||
//go:linkname runtimePanic runtime.runtimePanic
|
||||
func runtimePanic(str string)
|
||||
|
||||
// state is a structure which holds a reference to the state of the task.
|
||||
// When the task is suspended, the stack pointers are saved here.
|
||||
type state struct {
|
||||
|
||||
@@ -7,6 +7,9 @@ import "unsafe"
|
||||
// There is only one goroutine so the task struct can be a global.
|
||||
var mainTask Task
|
||||
|
||||
//go:linkname runtimePanic runtime.runtimePanic
|
||||
func runtimePanic(str string)
|
||||
|
||||
func Pause() {
|
||||
runtimePanic("scheduler is disabled")
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build scheduler.tasks || scheduler.cores
|
||||
//go:build scheduler.tasks
|
||||
|
||||
package task
|
||||
|
||||
@@ -7,6 +7,14 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//go:linkname runtimePanic runtime.runtimePanic
|
||||
func runtimePanic(str string)
|
||||
|
||||
// Stack canary, to detect a stack overflow. The number is a random number
|
||||
// generated by random.org. The bit fiddling dance is necessary because
|
||||
// otherwise Go wouldn't allow the cast to a smaller integer size.
|
||||
const stackCanary = uintptr(uint64(0x670c1333b83bf575) & uint64(^uintptr(0)))
|
||||
|
||||
// state is a structure which holds a reference to the state of the task.
|
||||
// When the task is suspended, the registers are stored onto the stack and the stack pointer is stored into sp.
|
||||
type state struct {
|
||||
@@ -25,54 +33,40 @@ type state struct {
|
||||
}
|
||||
|
||||
// currentTask is the current running task, or nil if currently in the scheduler.
|
||||
//var currentTask *Task
|
||||
var currentTask *Task
|
||||
|
||||
// Current returns the current active task.
|
||||
//func Current() *Task {
|
||||
// return currentTask
|
||||
//}
|
||||
|
||||
//go:linkname Current runtime.currentTask
|
||||
func Current() *Task
|
||||
|
||||
//go:linkname schedulerLock runtime.schedulerLock
|
||||
func schedulerLock()
|
||||
|
||||
func Pause() {
|
||||
schedulerLock()
|
||||
PauseLocked()
|
||||
func Current() *Task {
|
||||
return currentTask
|
||||
}
|
||||
|
||||
// Pause suspends the current task and returns to the scheduler.
|
||||
// This function may only be called when running on a goroutine stack, not when running on the system stack or in an interrupt.
|
||||
func PauseLocked() {
|
||||
func Pause() {
|
||||
// Check whether the canary (the lowest address of the stack) is still
|
||||
// valid. If it is not, a stack overflow has occurred.
|
||||
if *Current().state.canaryPtr != stackCanary {
|
||||
if *currentTask.state.canaryPtr != stackCanary {
|
||||
runtimePanic("goroutine stack overflow")
|
||||
}
|
||||
if interrupt.In() {
|
||||
runtimePanic("blocked inside interrupt")
|
||||
}
|
||||
current := Current()
|
||||
current.RunState = RunStatePaused
|
||||
current.state.pause()
|
||||
currentTask.state.pause()
|
||||
}
|
||||
|
||||
//export tinygo_task_exit
|
||||
func taskExit() {
|
||||
println("-- exiting task")
|
||||
//export tinygo_pause
|
||||
func pause() {
|
||||
Pause()
|
||||
}
|
||||
|
||||
// Resume the task until it pauses or completes.
|
||||
// This may only be called from the scheduler.
|
||||
func (t *Task) Resume() {
|
||||
//currentTask = t
|
||||
//t.gcData.swap()
|
||||
currentTask = t
|
||||
t.gcData.swap()
|
||||
t.state.resume()
|
||||
//t.gcData.swap()
|
||||
//currentTask = nil
|
||||
t.gcData.swap()
|
||||
currentTask = nil
|
||||
}
|
||||
|
||||
// initialize the state and prepare to call the specified function with the specified argument bundle.
|
||||
|
||||
@@ -28,7 +28,7 @@ tinygo_startTask:
|
||||
blx r4
|
||||
|
||||
// After return, exit this goroutine. This is a tail call.
|
||||
bl tinygo_task_exit
|
||||
bl tinygo_pause
|
||||
.cfi_endproc
|
||||
.size tinygo_startTask, .-tinygo_startTask
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build (scheduler.tasks || scheduler.cores) && cortexm
|
||||
//go:build scheduler.tasks && cortexm
|
||||
|
||||
package task
|
||||
|
||||
|
||||
@@ -1,113 +0,0 @@
|
||||
//go:build none
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// BDWGC also uses SIGRTMIN+6 on Linux, which seems like a reasonable choice.
|
||||
#ifdef __linux__
|
||||
#define taskPauseSignal (SIGRTMIN + 6)
|
||||
#endif
|
||||
|
||||
// Pointer to the current task.Task structure.
|
||||
// Ideally the entire task.Task structure would be a thread-local variable but
|
||||
// this also works.
|
||||
static __thread void *current_task;
|
||||
|
||||
struct state_pass {
|
||||
void *(*start)(void*);
|
||||
void *args;
|
||||
void *task;
|
||||
uintptr_t *stackTop;
|
||||
sem_t startlock;
|
||||
};
|
||||
|
||||
// Handle the GC pause in Go.
|
||||
void tinygo_task_gc_pause(int sig);
|
||||
|
||||
// Initialize the main thread.
|
||||
void tinygo_task_init(void *mainTask, pthread_t *thread, int *numCPU, void *context) {
|
||||
// Make sure the current task pointer is set correctly for the main
|
||||
// goroutine as well.
|
||||
current_task = mainTask;
|
||||
|
||||
// Store the thread ID of the main thread.
|
||||
*thread = pthread_self();
|
||||
|
||||
// Register the "GC pause" signal for the entire process.
|
||||
// Using pthread_kill, we can still send the signal to a specific thread.
|
||||
struct sigaction act = { 0 };
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
act.sa_handler = &tinygo_task_gc_pause;
|
||||
sigaction(taskPauseSignal, &act, NULL);
|
||||
|
||||
// Obtain the number of CPUs available on program start (for NumCPU).
|
||||
int num = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
if (num <= 0) {
|
||||
// Fallback in case there is an error.
|
||||
num = 1;
|
||||
}
|
||||
*numCPU = num;
|
||||
}
|
||||
|
||||
void tinygo_task_exited(void*);
|
||||
|
||||
// Helper to start a goroutine while also storing the 'task' structure.
|
||||
static void* start_wrapper(void *arg) {
|
||||
struct state_pass *state = arg;
|
||||
void *(*start)(void*) = state->start;
|
||||
void *args = state->args;
|
||||
current_task = state->task;
|
||||
|
||||
// Save the current stack pointer in the goroutine state, for the GC.
|
||||
int stackAddr;
|
||||
*(state->stackTop) = (uintptr_t)(&stackAddr);
|
||||
|
||||
// Notify the caller that the thread has successfully started and
|
||||
// initialized.
|
||||
sem_post(&state->startlock);
|
||||
|
||||
// Run the goroutine function.
|
||||
start(args);
|
||||
|
||||
// Notify the Go side this thread will exit.
|
||||
tinygo_task_exited(current_task);
|
||||
|
||||
return NULL;
|
||||
};
|
||||
|
||||
// Start a new goroutine in an OS thread.
|
||||
int tinygo_task_start(uintptr_t fn, void *args, void *task, pthread_t *thread, uintptr_t *stackTop, void *context) {
|
||||
// Sanity check. Should get optimized away.
|
||||
if (sizeof(pthread_t) != sizeof(void*)) {
|
||||
__builtin_trap();
|
||||
}
|
||||
|
||||
struct state_pass state = {
|
||||
.start = (void*)fn,
|
||||
.args = args,
|
||||
.task = task,
|
||||
.stackTop = stackTop,
|
||||
};
|
||||
sem_init(&state.startlock, 0, 0);
|
||||
int result = pthread_create(thread, NULL, &start_wrapper, &state);
|
||||
|
||||
// Wait until the thread has been created and read all state_pass variables.
|
||||
sem_wait(&state.startlock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Return the current task (for task.Current()).
|
||||
void* tinygo_task_current(void) {
|
||||
return current_task;
|
||||
}
|
||||
|
||||
// Send a signal to cause the task to pause for the GC mark phase.
|
||||
void tinygo_task_send_gc_signal(pthread_t thread) {
|
||||
pthread_kill(thread, taskPauseSignal);
|
||||
}
|
||||
@@ -1,268 +0,0 @@
|
||||
//go:build scheduler.threads
|
||||
|
||||
package task
|
||||
|
||||
import (
|
||||
"sync/atomic"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// If true, print verbose debug logs.
|
||||
const verbose = false
|
||||
|
||||
// Scheduler-specific state.
|
||||
type state struct {
|
||||
// Goroutine ID. The number here is not really significant and after a while
|
||||
// it could wrap around. But it is useful for debugging.
|
||||
id uintptr
|
||||
|
||||
// Thread ID, pthread_t or similar (typically implemented as a pointer).
|
||||
thread threadID
|
||||
|
||||
// Highest address of the stack. It is stored when the goroutine starts, and
|
||||
// is needed to be able to scan the stack.
|
||||
stackTop uintptr
|
||||
|
||||
// Next task in the activeTasks queue.
|
||||
QueueNext *Task
|
||||
|
||||
// Semaphore to pause/resume the thread atomically.
|
||||
pauseSem Semaphore
|
||||
|
||||
// Semaphore used for stack scanning.
|
||||
// We can't reuse pauseSem here since the thread might have been paused for
|
||||
// other reasons (for example, because it was waiting on a channel).
|
||||
gcSem Semaphore
|
||||
}
|
||||
|
||||
// Goroutine counter, starting at 0 for the main goroutine.
|
||||
var goroutineID uintptr
|
||||
|
||||
var numCPU int32
|
||||
|
||||
var mainTask Task
|
||||
|
||||
// Queue of tasks (see QueueNext) that currently exist in the program.
|
||||
var activeTasks = &mainTask
|
||||
var activeTaskLock PMutex
|
||||
|
||||
func OnSystemStack() bool {
|
||||
runtimePanic("todo: task.OnSystemStack")
|
||||
return false
|
||||
}
|
||||
|
||||
// Initialize the main goroutine state. Must be called by the runtime on
|
||||
// startup, before starting any other goroutines.
|
||||
func Init(sp uintptr) {
|
||||
mainTask.state.stackTop = sp
|
||||
tinygo_task_init(&mainTask, &mainTask.state.thread, &numCPU)
|
||||
}
|
||||
|
||||
// Return the task struct for the current thread.
|
||||
func Current() *Task {
|
||||
t := (*Task)(tinygo_task_current())
|
||||
if t == nil {
|
||||
runtimePanic("unknown current task")
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
// Pause pauses the current task, until it is resumed by another task.
|
||||
// It is possible that another task has called Resume() on the task before it
|
||||
// hits Pause(), in which case the task won't be paused but continues
|
||||
// immediately.
|
||||
func Pause() {
|
||||
// Wait until resumed
|
||||
t := Current()
|
||||
if verbose {
|
||||
println("*** pause: ", t.state.id)
|
||||
}
|
||||
t.state.pauseSem.Wait()
|
||||
}
|
||||
|
||||
// Resume the given task.
|
||||
// It is legal to resume a task before it gets paused, it means that the next
|
||||
// call to Pause() won't pause but will continue immediately. This happens in
|
||||
// practice sometimes in channel operations, where the Resume() might get called
|
||||
// between the channel unlock and the call to Pause().
|
||||
func (t *Task) Resume() {
|
||||
if verbose {
|
||||
println("*** resume: ", t.state.id)
|
||||
}
|
||||
// Increment the semaphore counter.
|
||||
// If the task is currently paused in Wait(), it will resume.
|
||||
// If the task is not yet paused, the next call to Wait() will continue
|
||||
// immediately.
|
||||
t.state.pauseSem.Post()
|
||||
}
|
||||
|
||||
// Start a new OS thread.
|
||||
func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
||||
t := &Task{}
|
||||
t.state.id = atomic.AddUintptr(&goroutineID, 1)
|
||||
if verbose {
|
||||
println("*** start: ", t.state.id, "from", Current().state.id)
|
||||
}
|
||||
|
||||
// Start the new thread, and add it to the list of threads.
|
||||
// Do this with a lock so that only started threads are part of the queue
|
||||
// and the stop-the-world GC won't see threads that haven't started yet or
|
||||
// are not fully started yet.
|
||||
activeTaskLock.Lock()
|
||||
errCode := tinygo_task_start(fn, args, t, &t.state.thread, &t.state.stackTop)
|
||||
if errCode != 0 {
|
||||
runtimePanic("could not start thread")
|
||||
}
|
||||
t.state.QueueNext = activeTasks
|
||||
activeTasks = t
|
||||
activeTaskLock.Unlock()
|
||||
}
|
||||
|
||||
//export tinygo_task_exited
|
||||
func taskExited(t *Task) {
|
||||
if verbose {
|
||||
println("*** exit:", t.state.id)
|
||||
}
|
||||
|
||||
// Remove from the queue.
|
||||
// TODO: this can be made more efficient by using a doubly linked list.
|
||||
activeTaskLock.Lock()
|
||||
found := false
|
||||
for q := &activeTasks; *q != nil; q = &(*q).state.QueueNext {
|
||||
if *q == t {
|
||||
*q = t.state.QueueNext
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
activeTaskLock.Unlock()
|
||||
|
||||
// Sanity check.
|
||||
if !found {
|
||||
runtimePanic("taskExited failed")
|
||||
}
|
||||
}
|
||||
|
||||
// Futex to wait on until all tasks have finished scanning the stack.
|
||||
// This is basically a sync.WaitGroup.
|
||||
var scanDoneFutex Futex
|
||||
|
||||
// GC scan phase. Because we need to stop the world while scanning, this kinda
|
||||
// needs to be done in the tasks package.
|
||||
func GCScan() {
|
||||
current := Current()
|
||||
|
||||
// Don't allow new goroutines to be started while pausing/resuming threads
|
||||
// in the stop-the-world phase.
|
||||
activeTaskLock.Lock()
|
||||
|
||||
// Pause all other threads.
|
||||
numOtherThreads := uint32(0)
|
||||
for t := activeTasks; t != nil; t = t.state.QueueNext {
|
||||
if t != current {
|
||||
numOtherThreads++
|
||||
tinygo_task_send_gc_signal(t.state.thread)
|
||||
}
|
||||
}
|
||||
|
||||
// Store the number of threads to wait for in the futex.
|
||||
// This is the equivalent of doing an initial wg.Add(numOtherThreads).
|
||||
scanDoneFutex.Store(numOtherThreads)
|
||||
|
||||
// Scan the current stack, and all current registers.
|
||||
scanCurrentStack()
|
||||
|
||||
// Wake each paused thread for the first time so it will scan the stack.
|
||||
for t := activeTasks; t != nil; t = t.state.QueueNext {
|
||||
if t != current {
|
||||
t.state.gcSem.Post()
|
||||
}
|
||||
}
|
||||
|
||||
// Wait until all threads have finished scanning their stack.
|
||||
// This is the equivalent of wg.Wait()
|
||||
for {
|
||||
val := scanDoneFutex.Load()
|
||||
if val == 0 {
|
||||
break
|
||||
}
|
||||
scanDoneFutex.Wait(val)
|
||||
}
|
||||
|
||||
// Scan all globals (implemented in the runtime).
|
||||
gcScanGlobals()
|
||||
|
||||
// Wake each paused thread for the second time, so they will resume normal
|
||||
// operation.
|
||||
for t := activeTasks; t != nil; t = t.state.QueueNext {
|
||||
if t != current {
|
||||
t.state.gcSem.Post()
|
||||
}
|
||||
}
|
||||
|
||||
// Allow goroutines to start and exit again.
|
||||
activeTaskLock.Unlock()
|
||||
}
|
||||
|
||||
// Scan globals, implemented in the runtime package.
|
||||
func gcScanGlobals()
|
||||
|
||||
var stackScanLock PMutex
|
||||
|
||||
//export tinygo_task_gc_pause
|
||||
func tingyo_task_gc_pause() {
|
||||
// Wait until we get the signal to start scanning the stack.
|
||||
Current().state.gcSem.Wait()
|
||||
|
||||
// Scan the thread stack.
|
||||
// Only scan a single thread stack at a time, because the GC marking phase
|
||||
// doesn't support parallelism.
|
||||
// TODO: it may be possible to call markRoots directly (without saving
|
||||
// registers) since we are in a signal handler that already saved a bunch of
|
||||
// registers. This is an optimization left for a future time.
|
||||
stackScanLock.Lock()
|
||||
scanCurrentStack()
|
||||
stackScanLock.Unlock()
|
||||
|
||||
// Equivalent of wg.Done(): subtract one from the futex and if the result is
|
||||
// 0 (meaning we were the last in the waitgroup), wake the waiting thread.
|
||||
n := uint32(1)
|
||||
if scanDoneFutex.Add(-n) == 0 {
|
||||
scanDoneFutex.Wake()
|
||||
}
|
||||
|
||||
// Wait until we get the signal we can resume normally (after the mark phase
|
||||
// has finished).
|
||||
Current().state.gcSem.Wait()
|
||||
}
|
||||
|
||||
//go:export tinygo_scanCurrentStack
|
||||
func scanCurrentStack()
|
||||
|
||||
// Return the highest address of the current stack.
|
||||
func StackTop() uintptr {
|
||||
return Current().state.stackTop
|
||||
}
|
||||
|
||||
// Using //go:linkname instead of //export so that we don't tell the compiler
|
||||
// that the 't' parameter won't escape (because it will).
|
||||
//
|
||||
//go:linkname tinygo_task_init tinygo_task_init
|
||||
func tinygo_task_init(t *Task, thread *threadID, numCPU *int32)
|
||||
|
||||
// Here same as for tinygo_task_init.
|
||||
//
|
||||
//go:linkname tinygo_task_start tinygo_task_start
|
||||
func tinygo_task_start(fn uintptr, args unsafe.Pointer, t *Task, thread *threadID, stackTop *uintptr) int32
|
||||
|
||||
// Pause the thread by sending it a signal.
|
||||
//
|
||||
//export tinygo_task_send_gc_signal
|
||||
func tinygo_task_send_gc_signal(threadID)
|
||||
|
||||
//export tinygo_task_current
|
||||
func tinygo_task_current() unsafe.Pointer
|
||||
|
||||
func NumCPU() int {
|
||||
return int(numCPU)
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
//go:build hw_651
|
||||
|
||||
package machine
|
||||
|
||||
// No-name brand board based on the nRF51822 chip with low frequency crystal on board.
|
||||
// Pinout (reverse engineered from the board) can be found here:
|
||||
// https://aviatorahmet.blogspot.com/2020/12/pinout-of-nrf51822-board.html
|
||||
// https://cr0wg4n.medium.com/pinout-nrf51822-board-hw-651-78da2eda8894
|
||||
|
||||
const HasLowFrequencyCrystal = true
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
// GPIO pins on header J1
|
||||
const (
|
||||
J1_01 = P0_21
|
||||
J1_03 = P0_23
|
||||
J1_04 = P0_22
|
||||
J1_05 = P0_25
|
||||
J1_06 = P0_24
|
||||
J1_09 = P0_29
|
||||
J1_10 = P0_28
|
||||
J1_11 = P0_30
|
||||
J1_13 = P0_00
|
||||
J1_15 = P0_02
|
||||
J1_17 = P0_04
|
||||
J1_16 = P0_01
|
||||
J1_18 = P0_03
|
||||
)
|
||||
|
||||
// GPIO pins on header J2
|
||||
const (
|
||||
J2_01 = P0_20
|
||||
J2_03 = P0_18
|
||||
J2_04 = P0_19
|
||||
J2_07 = P0_16
|
||||
J2_08 = P0_15
|
||||
J2_09 = P0_14
|
||||
J2_10 = P0_13
|
||||
J2_11 = P0_12
|
||||
J2_12 = P0_11
|
||||
J2_13 = P0_10
|
||||
J2_14 = P0_09
|
||||
J2_15 = P0_08
|
||||
J2_16 = P0_07
|
||||
J2_17 = P0_06
|
||||
J2_18 = P0_05
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART_TX_PIN = P0_24 // J1_06 on the board
|
||||
UART_RX_PIN = P0_25 // J1_05 on the board
|
||||
)
|
||||
|
||||
// ADC pins
|
||||
const (
|
||||
ADC0 = P0_03 // J1_18 on the board
|
||||
ADC1 = P0_02 // J1_15 on the board
|
||||
ADC2 = P0_01 // J1_16 on the board
|
||||
ADC3 = P0_04 // J1_17 on the board
|
||||
ADC4 = P0_05 // J2_18 on the board
|
||||
ADC5 = P0_06 // J2_17 on the board
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
SDA_PIN = P0_30 // J1_11 on the board
|
||||
SCL_PIN = P0_00 // J1_13 on the board
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI0_SCK_PIN = P0_23 // J1_03 on the board
|
||||
SPI0_SDO_PIN = P0_21 // J1_01 on the board
|
||||
SPI0_SDI_PIN = P0_22 // J1_04 on the board
|
||||
)
|
||||
@@ -0,0 +1,98 @@
|
||||
//go:build pga2350
|
||||
|
||||
package machine
|
||||
|
||||
// PGA2350 pin definitions.
|
||||
const (
|
||||
GP0 = GPIO0
|
||||
GP1 = GPIO1
|
||||
GP2 = GPIO2
|
||||
GP3 = GPIO3
|
||||
GP4 = GPIO4
|
||||
GP5 = GPIO5
|
||||
GP6 = GPIO6
|
||||
GP7 = GPIO7
|
||||
GP8 = GPIO8
|
||||
GP9 = GPIO9
|
||||
GP10 = GPIO10
|
||||
GP11 = GPIO11
|
||||
GP12 = GPIO12
|
||||
GP13 = GPIO13
|
||||
GP14 = GPIO14
|
||||
GP15 = GPIO15
|
||||
GP16 = GPIO16
|
||||
GP17 = GPIO17
|
||||
GP18 = GPIO18
|
||||
GP19 = GPIO19
|
||||
GP20 = GPIO20
|
||||
GP21 = GPIO21
|
||||
GP22 = GPIO22
|
||||
GP26 = GPIO26
|
||||
GP27 = GPIO27
|
||||
GP28 = GPIO28
|
||||
GP29 = GPIO29
|
||||
GP30 = GPIO30 // peripherals: PWM7 channel A
|
||||
GP31 = GPIO31 // peripherals: PWM7 channel B
|
||||
GP32 = GPIO32 // peripherals: PWM8 channel A
|
||||
GP33 = GPIO33 // peripherals: PWM8 channel B
|
||||
GP34 = GPIO34 // peripherals: PWM9 channel A
|
||||
GP35 = GPIO35 // peripherals: PWM9 channel B
|
||||
GP36 = GPIO36 // peripherals: PWM10 channel A
|
||||
GP37 = GPIO37 // peripherals: PWM10 channel B
|
||||
GP38 = GPIO38 // peripherals: PWM11 channel A
|
||||
GP39 = GPIO39 // peripherals: PWM11 channel B
|
||||
GP40 = GPIO40 // peripherals: PWM8 channel A
|
||||
GP41 = GPIO41 // peripherals: PWM8 channel B
|
||||
GP42 = GPIO42 // peripherals: PWM9 channel A
|
||||
GP43 = GPIO43 // peripherals: PWM9 channel B
|
||||
GP44 = GPIO44 // peripherals: PWM10 channel A
|
||||
GP45 = GPIO45 // peripherals: PWM10 channel B
|
||||
GP46 = GPIO46 // peripherals: PWM11 channel A
|
||||
GP47 = GPIO47 // peripherals: PWM11 channel B
|
||||
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
// Peripheral defaults.
|
||||
const (
|
||||
xoscFreq = 12 // MHz
|
||||
|
||||
I2C0_SDA_PIN = GP4
|
||||
I2C0_SCL_PIN = GP5
|
||||
|
||||
I2C1_SDA_PIN = GP2
|
||||
I2C1_SCL_PIN = GP3
|
||||
|
||||
// Default Serial Clock Bus 0 for SPI communications
|
||||
SPI0_SCK_PIN = GPIO18
|
||||
// Default Serial Out Bus 0 for SPI communications
|
||||
SPI0_SDO_PIN = GPIO19 // Tx
|
||||
// Default Serial In Bus 0 for SPI communications
|
||||
SPI0_SDI_PIN = GPIO16 // Rx
|
||||
|
||||
// Default Serial Clock Bus 1 for SPI communications
|
||||
SPI1_SCK_PIN = GPIO10
|
||||
// Default Serial Out Bus 1 for SPI communications
|
||||
SPI1_SDO_PIN = GPIO11 // Tx
|
||||
// Default Serial In Bus 1 for SPI communications
|
||||
SPI1_SDI_PIN = GPIO12 // Rx
|
||||
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART1_TX_PIN = GPIO8
|
||||
UART1_RX_PIN = GPIO9
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
// USB identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "PGA2350"
|
||||
usb_STRING_MANUFACTURER = "Pimoroni"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x2E8A
|
||||
usb_PID uint16 = 0x000A
|
||||
)
|
||||
@@ -0,0 +1,93 @@
|
||||
//go:build pico_plus2
|
||||
|
||||
package machine
|
||||
|
||||
// GPIO pins
|
||||
const (
|
||||
GP0 Pin = GPIO0
|
||||
GP1 Pin = GPIO1
|
||||
GP2 Pin = GPIO2
|
||||
GP3 Pin = GPIO3
|
||||
GP4 Pin = GPIO4
|
||||
GP5 Pin = GPIO5
|
||||
GP6 Pin = GPIO6
|
||||
GP7 Pin = GPIO7
|
||||
GP8 Pin = GPIO8
|
||||
GP9 Pin = GPIO9
|
||||
GP10 Pin = GPIO10
|
||||
GP11 Pin = GPIO11
|
||||
GP12 Pin = GPIO12
|
||||
GP13 Pin = GPIO13
|
||||
GP14 Pin = GPIO14
|
||||
GP15 Pin = GPIO15
|
||||
GP16 Pin = GPIO16
|
||||
GP17 Pin = GPIO17
|
||||
GP18 Pin = GPIO18
|
||||
GP19 Pin = GPIO19
|
||||
GP20 Pin = GPIO20
|
||||
GP21 Pin = GPIO21
|
||||
GP22 Pin = GPIO22
|
||||
GP26 Pin = GPIO26
|
||||
GP27 Pin = GPIO27
|
||||
GP28 Pin = GPIO28
|
||||
GP32 Pin = GPIO32
|
||||
GP33 Pin = GPIO33
|
||||
GP34 Pin = GPIO34
|
||||
GP35 Pin = GPIO35
|
||||
GP36 Pin = GPIO36
|
||||
|
||||
// Onboard LED
|
||||
LED Pin = GPIO25
|
||||
|
||||
// Onboard crystal oscillator frequency, in MHz.
|
||||
xoscFreq = 12 // MHz
|
||||
)
|
||||
|
||||
// I2C Default pins on Raspberry Pico.
|
||||
const (
|
||||
I2C0_SDA_PIN = GP4
|
||||
I2C0_SCL_PIN = GP5
|
||||
|
||||
I2C1_SDA_PIN = GP2
|
||||
I2C1_SCL_PIN = GP3
|
||||
)
|
||||
|
||||
// SPI default pins
|
||||
const (
|
||||
// Default Serial Clock Bus 0 for SPI communications
|
||||
SPI0_SCK_PIN = GPIO18
|
||||
// Default Serial Out Bus 0 for SPI communications
|
||||
SPI0_SDO_PIN = GPIO19 // Tx
|
||||
// Default Serial In Bus 0 for SPI communications
|
||||
SPI0_SDI_PIN = GPIO16 // Rx
|
||||
|
||||
// Default Serial Clock Bus 1 for SPI communications
|
||||
SPI1_SCK_PIN = GPIO10
|
||||
// Default Serial Out Bus 1 for SPI communications
|
||||
SPI1_SDO_PIN = GPIO11 // Tx
|
||||
// Default Serial In Bus 1 for SPI communications
|
||||
SPI1_SDI_PIN = GPIO12 // Rx
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
UART0_TX_PIN = GPIO0
|
||||
UART0_RX_PIN = GPIO1
|
||||
UART1_TX_PIN = GPIO8
|
||||
UART1_RX_PIN = GPIO9
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
// USB identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "Pico Plus2"
|
||||
usb_STRING_MANUFACTURER = "Pimoroni"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x2E8A
|
||||
usb_PID uint16 = 0x000F
|
||||
)
|
||||
@@ -64,3 +64,14 @@ type BlockDevice interface {
|
||||
// EraseBlockSize to map addresses to blocks.
|
||||
EraseBlocks(start, len int64) error
|
||||
}
|
||||
|
||||
// pad data if needed so it is long enough for correct byte alignment on writes.
|
||||
func flashPad(p []byte, writeBlockSize int) []byte {
|
||||
overflow := len(p) % writeBlockSize
|
||||
if overflow != 0 {
|
||||
for i := 0; i < writeBlockSize-overflow; i++ {
|
||||
p = append(p, 0xff)
|
||||
}
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
package machine
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"device/arm"
|
||||
"device/sam"
|
||||
"errors"
|
||||
@@ -1917,7 +1916,7 @@ func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
f.ensureInitComplete()
|
||||
|
||||
address := FlashDataStart() + uintptr(off)
|
||||
padded := f.pad(p)
|
||||
padded := flashPad(p, int(f.WriteBlockSize()))
|
||||
|
||||
waitWhileFlashBusy()
|
||||
|
||||
@@ -1992,17 +1991,6 @@ func (f flashBlockDevice) EraseBlocks(start, len int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// pad data if needed so it is long enough for correct byte alignment on writes.
|
||||
func (f flashBlockDevice) pad(p []byte) []byte {
|
||||
overflow := int64(len(p)) % f.WriteBlockSize()
|
||||
if overflow == 0 {
|
||||
return p
|
||||
}
|
||||
|
||||
padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow))
|
||||
return append(p, padding...)
|
||||
}
|
||||
|
||||
func (f flashBlockDevice) ensureInitComplete() {
|
||||
if f.initComplete {
|
||||
return
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
package machine
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"device/arm"
|
||||
"device/sam"
|
||||
"errors"
|
||||
@@ -2174,7 +2173,7 @@ func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
}
|
||||
|
||||
address := FlashDataStart() + uintptr(off)
|
||||
padded := f.pad(p)
|
||||
padded := flashPad(p, int(f.WriteBlockSize()))
|
||||
|
||||
settings := disableFlashCache()
|
||||
defer restoreFlashCache(settings)
|
||||
@@ -2263,17 +2262,6 @@ func (f flashBlockDevice) EraseBlocks(start, len int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// pad data if needed so it is long enough for correct byte alignment on writes.
|
||||
func (f flashBlockDevice) pad(p []byte) []byte {
|
||||
overflow := int64(len(p)) % f.WriteBlockSize()
|
||||
if overflow == 0 {
|
||||
return p
|
||||
}
|
||||
|
||||
padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow))
|
||||
return append(p, padding...)
|
||||
}
|
||||
|
||||
func disableFlashCache() uint16 {
|
||||
settings := sam.NVMCTRL.CTRLA.Get()
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
package machine
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"device/nrf"
|
||||
"internal/binary"
|
||||
"runtime/interrupt"
|
||||
@@ -386,7 +385,7 @@ func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
}
|
||||
|
||||
address := FlashDataStart() + uintptr(off)
|
||||
padded := f.pad(p)
|
||||
padded := flashPad(p, int(f.WriteBlockSize()))
|
||||
|
||||
waitWhileFlashBusy()
|
||||
|
||||
@@ -444,17 +443,6 @@ func (f flashBlockDevice) EraseBlocks(start, len int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// pad data if needed so it is long enough for correct byte alignment on writes.
|
||||
func (f flashBlockDevice) pad(p []byte) []byte {
|
||||
overflow := int64(len(p)) % f.WriteBlockSize()
|
||||
if overflow == 0 {
|
||||
return p
|
||||
}
|
||||
|
||||
padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow))
|
||||
return append(p, padding...)
|
||||
}
|
||||
|
||||
func waitWhileFlashBusy() {
|
||||
for nrf.NVMC.GetREADY() != nrf.NVMC_READY_READY_Ready {
|
||||
}
|
||||
|
||||
@@ -183,7 +183,12 @@ func (a *ADC) Get() uint16 {
|
||||
resolutionAdjustment = 4 // 12bit
|
||||
}
|
||||
|
||||
return rawValue.Get() << resolutionAdjustment
|
||||
value := int16(rawValue.Get())
|
||||
if value < 0 {
|
||||
value = 0
|
||||
}
|
||||
|
||||
return uint16(value << resolutionAdjustment)
|
||||
}
|
||||
|
||||
// SPI on the NRF.
|
||||
|
||||
@@ -16,6 +16,8 @@ const (
|
||||
// Note: On RP2350, most spinlocks are unusable due to Errata 2
|
||||
_NUMSPINLOCKS = 32
|
||||
_PICO_SPINLOCK_ID_IRQ = 9
|
||||
// is48Pin notes whether the chip is RP2040 with 32 pins or RP2350 with 48 pins.
|
||||
is48Pin = _NUMBANK0_GPIOS == 48
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
package machine
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -101,17 +100,6 @@ func (f flashBlockDevice) EraseBlocks(start, length int64) error {
|
||||
return f.eraseBlocks(start, length)
|
||||
}
|
||||
|
||||
// pad data if needed so it is long enough for correct byte alignment on writes.
|
||||
func (f flashBlockDevice) pad(p []byte) []byte {
|
||||
overflow := int64(len(p)) % f.WriteBlockSize()
|
||||
if overflow == 0 {
|
||||
return p
|
||||
}
|
||||
|
||||
padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow))
|
||||
return append(p, padding...)
|
||||
}
|
||||
|
||||
// return the correct address to be used for write
|
||||
func writeAddress(off int64) uintptr {
|
||||
return readAddress(off) - uintptr(memoryStart)
|
||||
|
||||
@@ -230,7 +230,7 @@ func (f flashBlockDevice) writeAt(p []byte, off int64) (n int, err error) {
|
||||
// e.g. real address 0x10003000 is written to at
|
||||
// 0x00003000
|
||||
address := writeAddress(off)
|
||||
padded := f.pad(p)
|
||||
padded := flashPad(p, int(f.WriteBlockSize()))
|
||||
|
||||
C.flash_range_write(C.uint32_t(address),
|
||||
(*C.uint8_t)(unsafe.Pointer(&padded[0])),
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
cpuFreq = 200 * MHz
|
||||
_NUMBANK0_GPIOS = 30
|
||||
_NUMBANK0_IRQS = 4
|
||||
_NUMIRQ = 32
|
||||
@@ -45,6 +46,16 @@ const (
|
||||
PinPIO1
|
||||
)
|
||||
|
||||
// Analog pins on RP2040.
|
||||
const (
|
||||
ADC0 Pin = GPIO26
|
||||
ADC1 Pin = GPIO27
|
||||
ADC2 Pin = GPIO28
|
||||
ADC3 Pin = GPIO29
|
||||
|
||||
thermADC = 30
|
||||
)
|
||||
|
||||
const (
|
||||
clkGPOUT0 clockIndex = iota // GPIO Muxing 0
|
||||
clkGPOUT1 // GPIO Muxing 1
|
||||
@@ -197,3 +208,16 @@ func (clks *clocksType) initTicks() {} // No ticks on RP2040
|
||||
func (wd *watchdogImpl) startTick(cycles uint32) {
|
||||
rp.WATCHDOG.TICK.Set(cycles | rp.WATCHDOG_TICK_ENABLE)
|
||||
}
|
||||
|
||||
func adjustCoreVoltage() bool {
|
||||
if cpuFreq <= 133*MHz {
|
||||
return false
|
||||
}
|
||||
// The rp2040 is certified to run at 200MHz with the
|
||||
// core voltage set to 1150mV.
|
||||
const targetVoltage = 1150
|
||||
// 0b0101 maps to 800mV and each step is 50mV.
|
||||
const vreg = 0b0101 + (targetVoltage-800)/50
|
||||
rp.VREG_AND_CHIP_RESET.SetVREG_VSEL(vreg)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
cpuFreq = 150 * MHz
|
||||
_NUMBANK0_GPIOS = 48
|
||||
_NUMBANK0_IRQS = 6
|
||||
rp2350ExtraReg = 1
|
||||
@@ -126,11 +127,17 @@ func (p Pin) Configure(config PinConfig) {
|
||||
return
|
||||
}
|
||||
p.init()
|
||||
mask := uint32(1) << p
|
||||
|
||||
switch config.Mode {
|
||||
case PinOutput:
|
||||
p.setFunc(fnSIO)
|
||||
rp.SIO.GPIO_OE_SET.Set(mask)
|
||||
if is48Pin && p >= 32 {
|
||||
mask := uint32(1) << (p % 32)
|
||||
rp.SIO.GPIO_HI_OE_SET.Set(mask)
|
||||
} else {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OE_SET.Set(mask)
|
||||
}
|
||||
case PinInput:
|
||||
p.setFunc(fnSIO)
|
||||
p.pulloff()
|
||||
@@ -215,3 +222,7 @@ func EnterBootloader() {
|
||||
func (wd *watchdogImpl) startTick(cycles uint32) {
|
||||
rp.TICKS.WATCHDOG_CTRL.SetBits(1)
|
||||
}
|
||||
|
||||
func adjustCoreVoltage() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
//go:build rp2350 && !rp2350b
|
||||
|
||||
package machine
|
||||
|
||||
// Analog pins on RP2350a.
|
||||
const (
|
||||
ADC0 Pin = GPIO26
|
||||
ADC1 Pin = GPIO27
|
||||
ADC2 Pin = GPIO28
|
||||
ADC3 Pin = GPIO29
|
||||
|
||||
// fifth ADC channel.
|
||||
thermADC = 30
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
//go:build rp2350b
|
||||
|
||||
package machine
|
||||
|
||||
// RP2350B has additional pins.
|
||||
|
||||
const (
|
||||
GPIO30 Pin = 30 // peripherals: PWM7 channel A
|
||||
GPIO31 Pin = 31 // peripherals: PWM7 channel B
|
||||
GPIO32 Pin = 32 // peripherals: PWM8 channel A
|
||||
GPIO33 Pin = 33 // peripherals: PWM8 channel B
|
||||
GPIO34 Pin = 34 // peripherals: PWM9 channel A
|
||||
GPIO35 Pin = 35 // peripherals: PWM9 channel B
|
||||
GPIO36 Pin = 36 // peripherals: PWM10 channel A
|
||||
GPIO37 Pin = 37 // peripherals: PWM10 channel B
|
||||
GPIO38 Pin = 38 // peripherals: PWM11 channel A
|
||||
GPIO39 Pin = 39 // peripherals: PWM11 channel B
|
||||
GPIO40 Pin = 40 // peripherals: PWM8 channel A
|
||||
GPIO41 Pin = 41 // peripherals: PWM8 channel B
|
||||
GPIO42 Pin = 42 // peripherals: PWM9 channel A
|
||||
GPIO43 Pin = 43 // peripherals: PWM9 channel B
|
||||
GPIO44 Pin = 44 // peripherals: PWM10 channel A
|
||||
GPIO45 Pin = 45 // peripherals: PWM10 channel B
|
||||
GPIO46 Pin = 46 // peripherals: PWM11 channel A
|
||||
GPIO47 Pin = 47 // peripherals: PWM11 channel B
|
||||
)
|
||||
|
||||
// Analog pins on 2350b.
|
||||
const (
|
||||
ADC0 Pin = GPIO40
|
||||
ADC1 Pin = GPIO41
|
||||
ADC2 Pin = GPIO42
|
||||
ADC3 Pin = GPIO43
|
||||
ADC4 Pin = GPIO44
|
||||
ADC5 Pin = GPIO45
|
||||
ADC6 Pin = GPIO46
|
||||
ADC7 Pin = GPIO47
|
||||
// Ninth ADC channel.
|
||||
thermADC = 48
|
||||
)
|
||||
|
||||
// Additional PWMs on the RP2350B.
|
||||
var (
|
||||
PWM8 = getPWMGroup(8)
|
||||
PWM9 = getPWMGroup(9)
|
||||
PWM10 = getPWMGroup(10)
|
||||
PWM11 = getPWMGroup(11)
|
||||
)
|
||||
@@ -11,15 +11,6 @@ import (
|
||||
// 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
|
||||
adcTempSensor // Internal temperature sensor channel
|
||||
)
|
||||
|
||||
// Used to serialise ADC sampling
|
||||
var adcLock sync.Mutex
|
||||
|
||||
@@ -58,20 +49,10 @@ func (a ADC) Get() uint16 {
|
||||
|
||||
// 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")
|
||||
if a.Pin < ADC0 {
|
||||
return 0, errors.New("no ADC channel for pin value")
|
||||
}
|
||||
return c, err
|
||||
return ADCChannel(a.Pin - ADC0), nil
|
||||
}
|
||||
|
||||
// Configure sets the channel's associated pin to analog input mode.
|
||||
@@ -113,12 +94,12 @@ func ReadTemperature() (millicelsius int32) {
|
||||
if rp.ADC.CS.Get()&rp.ADC_CS_EN == 0 {
|
||||
InitADC()
|
||||
}
|
||||
|
||||
thermChan, _ := ADC{Pin: thermADC}.GetADCChannel()
|
||||
// Enable temperature sensor bias source
|
||||
rp.ADC.CS.SetBits(rp.ADC_CS_TS_EN)
|
||||
|
||||
// T = 27 - (ADC_voltage - 0.706)/0.001721
|
||||
return (27000<<16 - (int32(adcTempSensor.getVoltage())-706<<16)*581) >> 16
|
||||
return (27000<<16 - (int32(thermChan.getVoltage())-706<<16)*581) >> 16
|
||||
}
|
||||
|
||||
// waitForReady spins waiting for the ADC peripheral to become ready.
|
||||
@@ -129,18 +110,5 @@ func waitForReady() {
|
||||
|
||||
// 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:
|
||||
err = errors.New("no associated pin for channel")
|
||||
}
|
||||
return p, err
|
||||
return Pin(c) + ADC0, nil
|
||||
}
|
||||
|
||||
@@ -10,13 +10,7 @@ import (
|
||||
)
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
return 125 * MHz
|
||||
}
|
||||
|
||||
// Returns the period of a clock cycle for the raspberry pi pico in nanoseconds.
|
||||
// Used in PWM API.
|
||||
func cpuPeriod() uint32 {
|
||||
return 1e9 / CPUFrequency()
|
||||
return cpuFreq
|
||||
}
|
||||
|
||||
// clockIndex identifies a hardware clock
|
||||
@@ -48,6 +42,10 @@ type clock struct {
|
||||
cix clockIndex
|
||||
}
|
||||
|
||||
// The delay in seconds for core voltage adjustments to
|
||||
// settle. Taken from the Pico SDK.
|
||||
const _VREG_VOLTAGE_AUTO_ADJUST_DELAY = 1 / 1e3
|
||||
|
||||
// clock returns the clock identified by cix.
|
||||
func (clks *clocksType) clock(cix clockIndex) clock {
|
||||
return clock{
|
||||
@@ -143,6 +141,20 @@ func (clk *clock) configure(src, auxsrc, srcFreq, freq uint32) {
|
||||
|
||||
}
|
||||
|
||||
var pllsysFB, pllsysPD1, pllsysPD2 uint32
|
||||
|
||||
// Compute clock dividers.
|
||||
//
|
||||
// Note that the entire init function is computed at compile time
|
||||
// by interp.
|
||||
func init() {
|
||||
fb, _, pd1, pd2, err := pllSearch{LockRefDiv: 1}.CalcDivs(xoscFreq*MHz, cpuFreq, MHz)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
pllsysFB, pllsysPD1, pllsysPD2 = uint32(fb), uint32(pd1), uint32(pd2)
|
||||
}
|
||||
|
||||
// init initializes the clock hardware.
|
||||
//
|
||||
// Must be called before any other clock function.
|
||||
@@ -169,23 +181,31 @@ func (clks *clocksType) init() {
|
||||
// REF FBDIV VCO POSTDIV
|
||||
// pllSys: 12 / 1 = 12MHz * 125 = 1500MHZ / 6 / 2 = 125MHz
|
||||
// pllUSB: 12 / 1 = 12MHz * 40 = 480 MHz / 5 / 2 = 48MHz
|
||||
pllSys.init(1, 1500*MHz, 6, 2)
|
||||
pllUSB.init(1, 480*MHz, 5, 2)
|
||||
pllSys.init(1, pllsysFB, pllsysPD1, pllsysPD2)
|
||||
pllUSB.init(1, 40, 5, 2)
|
||||
|
||||
// Configure clocks
|
||||
// clkRef = xosc (12MHz) / 1 = 12MHz
|
||||
cref := clks.clock(clkRef)
|
||||
cref.configure(rp.CLOCKS_CLK_REF_CTRL_SRC_XOSC_CLKSRC,
|
||||
0, // No aux mux
|
||||
12*MHz,
|
||||
12*MHz)
|
||||
xoscFreq,
|
||||
xoscFreq)
|
||||
|
||||
if adjustCoreVoltage() {
|
||||
// Wait for the voltage to settle.
|
||||
const cycles = _VREG_VOLTAGE_AUTO_ADJUST_DELAY * xoscFreq * MHz
|
||||
for i := 0; i < cycles; i++ {
|
||||
arm.Asm("nop")
|
||||
}
|
||||
}
|
||||
|
||||
// clkSys = pllSys (125MHz) / 1 = 125MHz
|
||||
csys := clks.clock(clkSys)
|
||||
csys.configure(rp.CLOCKS_CLK_SYS_CTRL_SRC_CLKSRC_CLK_SYS_AUX,
|
||||
rp.CLOCKS_CLK_SYS_CTRL_AUXSRC_CLKSRC_PLL_SYS,
|
||||
125*MHz,
|
||||
125*MHz)
|
||||
cpuFreq,
|
||||
cpuFreq)
|
||||
|
||||
// clkUSB = pllUSB (48MHz) / 1 = 48MHz
|
||||
cusb := clks.clock(clkUSB)
|
||||
@@ -209,8 +229,8 @@ func (clks *clocksType) init() {
|
||||
cperi := clks.clock(clkPeri)
|
||||
cperi.configure(0,
|
||||
rp.CLOCKS_CLK_PERI_CTRL_AUXSRC_CLK_SYS,
|
||||
125*MHz,
|
||||
125*MHz)
|
||||
cpuFreq,
|
||||
cpuFreq)
|
||||
|
||||
clks.initTicks()
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ type irqSummary struct {
|
||||
|
||||
type ioBank0Type struct {
|
||||
io [_NUMBANK0_GPIOS]ioType
|
||||
_ [rp2350ExtraReg][128]byte
|
||||
irqsum [rp2350ExtraReg]irqSummary
|
||||
intR [_NUMBANK0_IRQS]volatile.Register32
|
||||
proc0IRQctrl irqCtrl
|
||||
@@ -63,8 +64,13 @@ func (p Pin) PortMaskSet() (*uint32, uint32) {
|
||||
|
||||
// set drives the pin high
|
||||
func (p Pin) set() {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_SET.Set(mask)
|
||||
if is48Pin && p >= 32 {
|
||||
mask := uint32(1) << (p % 32)
|
||||
rp.SIO.GPIO_HI_OUT_SET.Set(mask)
|
||||
} else {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_SET.Set(mask)
|
||||
}
|
||||
}
|
||||
|
||||
func (p Pin) PortMaskClear() (*uint32, uint32) {
|
||||
@@ -73,18 +79,31 @@ func (p Pin) PortMaskClear() (*uint32, uint32) {
|
||||
|
||||
// clr drives the pin low
|
||||
func (p Pin) clr() {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_CLR.Set(mask)
|
||||
if is48Pin && p >= 32 {
|
||||
mask := uint32(1) << (p % 32)
|
||||
rp.SIO.GPIO_HI_OUT_CLR.Set(mask)
|
||||
} else {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_CLR.Set(mask)
|
||||
}
|
||||
}
|
||||
|
||||
// xor toggles the pin
|
||||
func (p Pin) xor() {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_XOR.Set(mask)
|
||||
if is48Pin && p >= 32 {
|
||||
mask := uint32(1) << (p % 32)
|
||||
rp.SIO.GPIO_HI_OUT_XOR.Set(mask)
|
||||
} else {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OUT_XOR.Set(mask)
|
||||
}
|
||||
}
|
||||
|
||||
// get returns the pin value
|
||||
func (p Pin) get() bool {
|
||||
if is48Pin && p >= 32 {
|
||||
return rp.SIO.GPIO_HI_IN.HasBits(1 << (p % 32))
|
||||
}
|
||||
return rp.SIO.GPIO_IN.HasBits(1 << p)
|
||||
}
|
||||
|
||||
@@ -134,8 +153,13 @@ func (p Pin) setFunc(fn pinFunc) {
|
||||
|
||||
// init initializes the gpio pin
|
||||
func (p Pin) init() {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OE_CLR.Set(mask)
|
||||
if is48Pin && p >= 32 {
|
||||
mask := uint32(1) << (p % 32)
|
||||
rp.SIO.GPIO_HI_OE_CLR.Set(mask)
|
||||
} else {
|
||||
mask := uint32(1) << p
|
||||
rp.SIO.GPIO_OE_CLR.Set(mask)
|
||||
}
|
||||
p.clr()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build rp2040 || rp2350 || ae_rp2040 || badger2040 || challenger_rp2040 || feather_rp2040 || gopher_badge || kb2040 || macropad_rp2040 || nano_rp2040 || pico || qtpy_rp2040 || thingplus_rp2040 || thumby || tufty2040 || waveshare_rp2040_zero || xiao_rp2040
|
||||
//go:build rp2040 || rp2350 || gopher_badge || pico
|
||||
|
||||
package machine
|
||||
|
||||
@@ -34,10 +34,4 @@ const (
|
||||
GPIO27 Pin = 27 // peripherals: PWM5 channel B
|
||||
GPIO28 Pin = 28 // peripherals: PWM6 channel A
|
||||
GPIO29 Pin = 29 // peripherals: PWM6 channel B
|
||||
|
||||
// Analog pins
|
||||
ADC0 Pin = GPIO26
|
||||
ADC1 Pin = GPIO27
|
||||
ADC2 Pin = GPIO28
|
||||
ADC3 Pin = GPIO29
|
||||
)
|
||||
|
||||
@@ -4,6 +4,9 @@ package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"errors"
|
||||
"math"
|
||||
"math/bits"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
@@ -29,12 +32,11 @@ var (
|
||||
// Post Divider 1, postDiv1 with range 1-7 and be >= postDiv2.
|
||||
//
|
||||
// Post Divider 2, postDiv2 with range 1-7.
|
||||
func (pll *pll) init(refdiv, vcoFreq, postDiv1, postDiv2 uint32) {
|
||||
func (pll *pll) init(refdiv, fbdiv, postDiv1, postDiv2 uint32) {
|
||||
refFreq := xoscFreq / refdiv
|
||||
|
||||
// What are we multiplying the reference clock by to get the vco freq
|
||||
// (The regs are called div, because you divide the vco output and compare it to the refclk)
|
||||
fbdiv := vcoFreq / (refFreq * MHz)
|
||||
|
||||
// Check fbdiv range
|
||||
if !(fbdiv >= 16 && fbdiv <= 320) {
|
||||
@@ -54,13 +56,14 @@ func (pll *pll) init(refdiv, vcoFreq, postDiv1, postDiv2 uint32) {
|
||||
panic("postdiv1 should be greater than or equal to postdiv2")
|
||||
}
|
||||
|
||||
// Check that reference frequency is no greater than vco / 16
|
||||
// Check that reference frequency is no greater than vcoFreq / 16
|
||||
vcoFreq := calcVCO(xoscFreq, fbdiv, refdiv)
|
||||
if refFreq > vcoFreq/16 {
|
||||
panic("reference frequency should not be greater than vco frequency divided by 16")
|
||||
}
|
||||
|
||||
// div1 feeds into div2 so if div1 is 5 and div2 is 2 then you get a divide by 10
|
||||
pdiv := postDiv1<<rp.PLL_SYS_PRIM_POSTDIV1_Pos | postDiv2<<rp.PLL_SYS_PRIM_POSTDIV2_Pos
|
||||
pdiv := uint32(postDiv1)<<rp.PLL_SYS_PRIM_POSTDIV1_Pos | uint32(postDiv2)<<rp.PLL_SYS_PRIM_POSTDIV2_Pos
|
||||
|
||||
if pll.cs.HasBits(rp.PLL_SYS_CS_LOCK) &&
|
||||
refdiv == pll.cs.Get()&rp.PLL_SYS_CS_REFDIV_Msk &&
|
||||
@@ -98,3 +101,179 @@ func (pll *pll) init(refdiv, vcoFreq, postDiv1, postDiv2 uint32) {
|
||||
pll.pwr.ClearBits(rp.PLL_SYS_PWR_POSTDIVPD)
|
||||
|
||||
}
|
||||
|
||||
var errVCOOverflow = errors.New("VCO calculation overflow; use lower MHz")
|
||||
|
||||
// pllSearch enables searching for a good PLL configuration.
|
||||
// Example for 12MHz crystal and RP2040:
|
||||
//
|
||||
// fbdiv, refdiv, pd1, pd2, _ := pllSearch{LockRefDiv:1}.CalcDivs(12*MHz, 125*MHz, MHz)
|
||||
//
|
||||
// Example for 12MHz crystal and RP2350:
|
||||
//
|
||||
// fbdiv, refdiv, pd1, pd2, _ := pllSearch{LockRefDiv:1}.CalcDivs(12*MHz, 150*MHz, MHz)
|
||||
type pllSearch struct {
|
||||
LowerVCO bool
|
||||
LockRefDiv uint8
|
||||
}
|
||||
|
||||
func (ps pllSearch) CalcDivs(xoscRef, targetFreq, MHz uint64) (fbdiv uint64, refdiv, pd1, pd2 uint8, err error) {
|
||||
genTable()
|
||||
var bestFreq, bestFbdiv uint64
|
||||
var bestRefdiv, bestpd1, bestpd2 uint8
|
||||
maxVCO, minVCO := 1600*MHz, 750*MHz
|
||||
var bestMargin int64 = int64(maxVCO)
|
||||
iters := 0
|
||||
for refdiv = 1; refdiv < 64; refdiv++ {
|
||||
if ps.LockRefDiv != 0 && refdiv != ps.LockRefDiv {
|
||||
continue
|
||||
}
|
||||
firstFBDiv := minVCO * uint64(refdiv) / xoscRef
|
||||
for fbdiv = firstFBDiv; fbdiv < 321; fbdiv++ {
|
||||
overflow, vco := bits.Mul64(xoscRef, fbdiv)
|
||||
vco /= uint64(refdiv)
|
||||
if overflow != 0 {
|
||||
return fbdiv, refdiv, pd1, pd2, errVCOOverflow
|
||||
} else if vco > maxVCO {
|
||||
break
|
||||
}
|
||||
calcPD12 := vco / targetFreq
|
||||
if calcPD12 < 1 {
|
||||
calcPD12 = 1
|
||||
} else if calcPD12 > 49 {
|
||||
calcPD12 = 49
|
||||
}
|
||||
iters++
|
||||
pd1 = pdTable[calcPD12].hivco[0]
|
||||
pd2 = pdTable[calcPD12].hivco[1]
|
||||
fout, err := pllFreqOutPostdiv(xoscRef, fbdiv, MHz, refdiv, pd1, pd2)
|
||||
found := false
|
||||
margin := abs(int64(fout) - int64(targetFreq))
|
||||
if err == nil && margin <= bestMargin {
|
||||
found = true
|
||||
bestFreq = fout
|
||||
bestFbdiv = fbdiv
|
||||
bestpd1 = pd1
|
||||
bestpd2 = pd2
|
||||
bestRefdiv = refdiv
|
||||
bestMargin = margin
|
||||
}
|
||||
pd1 = pdTable[calcPD12].lovco[0]
|
||||
pd2 = pdTable[calcPD12].lovco[1]
|
||||
fout, err = pllFreqOutPostdiv(xoscRef, fbdiv, MHz, refdiv, pd1, pd2)
|
||||
margin = abs(int64(fout) - int64(targetFreq))
|
||||
if err == nil && margin <= bestMargin {
|
||||
found = true
|
||||
bestFreq = fout
|
||||
bestFbdiv = fbdiv
|
||||
bestpd1 = pd1
|
||||
bestpd2 = pd2
|
||||
bestRefdiv = refdiv
|
||||
bestMargin = margin
|
||||
}
|
||||
if found && ps.LowerVCO {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if bestFreq == 0 {
|
||||
return fbdiv, refdiv, pd1, pd2, errors.New("no best frequency found")
|
||||
}
|
||||
return bestFbdiv, bestRefdiv, bestpd1, bestpd2, nil
|
||||
}
|
||||
|
||||
func abs(a int64) int64 {
|
||||
if a == math.MinInt64 {
|
||||
return math.MaxInt64
|
||||
} else if a < 0 {
|
||||
return -a
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func pllFreqOutPostdiv(xosc, fbdiv, MHz uint64, refdiv, postdiv1, postdiv2 uint8) (foutpostdiv uint64, err error) {
|
||||
// testing grounds.
|
||||
const (
|
||||
mhz = 1
|
||||
cfref = 12 * mhz // given by crystal oscillator selection.
|
||||
crefd = 1
|
||||
cfbdiv = 100
|
||||
cvco = cfref * cfbdiv / crefd
|
||||
cpd1 = 6
|
||||
cpd2 = 2
|
||||
foutpd = (cfref / crefd) * cfbdiv / (cpd1 * cpd2)
|
||||
)
|
||||
refFreq := xosc / uint64(refdiv)
|
||||
overflow, vco := bits.Mul64(xosc, fbdiv)
|
||||
vco /= uint64(refdiv)
|
||||
foutpostdiv = vco / uint64(postdiv1*postdiv2)
|
||||
switch {
|
||||
case refdiv < 1 || refdiv > 63:
|
||||
err = errors.New("reference divider out of range")
|
||||
case fbdiv < 16 || fbdiv > 320:
|
||||
err = errors.New("feedback divider out of range")
|
||||
case postdiv1 < 1 || postdiv1 > 7:
|
||||
err = errors.New("postdiv1 out of range")
|
||||
case postdiv2 < 1 || postdiv2 > 7:
|
||||
err = errors.New("postdiv2 out of range")
|
||||
case postdiv1 < postdiv2:
|
||||
err = errors.New("user error: use higher value for postdiv1 for lower power consumption")
|
||||
case vco < 750*MHz || vco > 1600*MHz:
|
||||
err = errors.New("VCO out of range")
|
||||
case refFreq < 5*MHz:
|
||||
err = errors.New("minimum reference frequency breach")
|
||||
case refFreq > vco/16:
|
||||
err = errors.New("maximum reference frequency breach")
|
||||
case vco > 1200*MHz && vco < 1600*MHz && xosc < 75*MHz && refdiv != 1:
|
||||
err = errors.New("refdiv should be 1 for given VCO and reference frequency")
|
||||
case overflow != 0:
|
||||
err = errVCOOverflow
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return foutpostdiv, nil
|
||||
}
|
||||
|
||||
func calcVCO(xoscFreq, fbdiv, refdiv uint32) uint32 {
|
||||
const maxXoscMHz = math.MaxUint32 / 320 / MHz // 13MHz maximum xosc apparently.
|
||||
if fbdiv > 320 || xoscFreq > math.MaxUint32/320 {
|
||||
panic("invalid VCO calculation args")
|
||||
}
|
||||
return xoscFreq * fbdiv / refdiv
|
||||
}
|
||||
|
||||
var pdTable = [50]struct {
|
||||
hivco [2]uint8
|
||||
lovco [2]uint8
|
||||
}{}
|
||||
|
||||
func genTable() {
|
||||
if pdTable[1].hivco[1] != 0 {
|
||||
return // Already generated.
|
||||
}
|
||||
for product := 1; product < len(pdTable); product++ {
|
||||
bestProdhi := 255
|
||||
bestProdlo := 255
|
||||
for pd1 := 7; pd1 > 0; pd1-- {
|
||||
for pd2 := pd1; pd2 > 0; pd2-- {
|
||||
gotprod := pd1 * pd2
|
||||
if abs(int64(gotprod-product)) < abs(int64(bestProdlo-product)) {
|
||||
bestProdlo = gotprod
|
||||
pdTable[product].lovco[0] = uint8(pd1)
|
||||
pdTable[product].lovco[1] = uint8(pd2)
|
||||
}
|
||||
}
|
||||
}
|
||||
for pd1 := 1; pd1 < 8; pd1++ {
|
||||
for pd2 := 1; pd2 <= pd1; pd2++ {
|
||||
gotprod := pd1 * pd2
|
||||
if abs(int64(gotprod-product)) < abs(int64(bestProdhi-product)) {
|
||||
bestProdhi = gotprod
|
||||
pdTable[product].hivco[0] = uint8(pd1)
|
||||
pdTable[product].hivco[1] = uint8(pd2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build rp2040
|
||||
//go:build rp2040 || rp2350
|
||||
|
||||
package machine
|
||||
|
||||
@@ -15,7 +15,7 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
maxPWMPins = 29
|
||||
maxPWMPins = _NUMBANK0_GPIOS - 1
|
||||
)
|
||||
|
||||
// pwmGroup is one PWM peripheral, which consists of a counter and two output
|
||||
@@ -146,12 +146,14 @@ func (p *pwmGroup) Counter() uint32 {
|
||||
|
||||
// Period returns the used PWM period in nanoseconds.
|
||||
func (p *pwmGroup) Period() uint64 {
|
||||
periodPerCycle := cpuPeriod()
|
||||
// Lines below can overflow if operations done without care.
|
||||
// maxInt=255, maxFrac=15, maxTop=65536, maxPHC=1 => maxProduct= (16*255+15) * (65536*2*1e9) = 5.3673e17 < MaxUint64=1.8e19 (close call.)
|
||||
const compileTimeCheckPeriod uint64 = (255*16 + 15) * (65535 + 1) * 2 * 1e9
|
||||
freq := uint64(CPUFrequency())
|
||||
top := p.getWrap()
|
||||
phc := p.getPhaseCorrect()
|
||||
Int, frac := p.getClockDiv()
|
||||
// Line below can overflow if operations done without care.
|
||||
return (16*uint64(Int) + uint64(frac)) * uint64((top+1)*(phc+1)*periodPerCycle) / 16 // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16)
|
||||
return (16*uint64(Int) + uint64(frac)) * uint64((top+1)*(phc+1)*1e9) / (16 * freq) // cycles = (TOP+1) * (CSRPHCorrect + 1) * (DIV_INT + DIV_FRAC/16)
|
||||
}
|
||||
|
||||
// SetInverting sets whether to invert the output of this channel.
|
||||
@@ -266,6 +268,9 @@ func (pwm *pwmGroup) setPeriod(period uint64) error {
|
||||
// Maximum Period is 268369920ns on rp2040, given by (16*255+15)*8*(1+0xffff)*(1+1)/16
|
||||
// With no phase shift max period is half of this value.
|
||||
maxPeriod = 268 * milliseconds
|
||||
// This will be a compile time error if this method is at risk of overflowing. cpufreq=155MHz for typical RP2350.
|
||||
maxCPUFreq = 4 * GHz // Can go up to 4GHz without overflowing :)
|
||||
compileTimeCheckSetPeriod uint64 = 16 * maxPeriod * maxCPUFreq
|
||||
)
|
||||
|
||||
if period > maxPeriod || period < 8 {
|
||||
@@ -279,11 +284,13 @@ func (pwm *pwmGroup) setPeriod(period uint64) error {
|
||||
// DIV_INT + DIV_FRAC/16 = cycles / ( (TOP+1) * (CSRPHCorrect+1) ) // DIV_FRAC/16 is always 0 in this equation
|
||||
// where cycles must be converted to time:
|
||||
// target_period = cycles * period_per_cycle ==> cycles = target_period/period_per_cycle
|
||||
periodPerCycle := uint64(cpuPeriod())
|
||||
phc := uint64(pwm.getPhaseCorrect())
|
||||
rhs := 16 * period / ((1 + phc) * periodPerCycle * (1 + topStart)) // right-hand-side of equation, scaled so frac is not divided
|
||||
whole := rhs / 16
|
||||
frac := rhs % 16
|
||||
var (
|
||||
freq = uint64(CPUFrequency())
|
||||
phc = uint64(pwm.getPhaseCorrect())
|
||||
rhs = 16 * period * freq / ((1 + phc) * 1e9 * (1 + topStart)) // right-hand-side of equation, scaled so frac is not divided
|
||||
whole = rhs / 16
|
||||
frac = rhs % 16
|
||||
)
|
||||
switch {
|
||||
case whole > 0xff:
|
||||
whole = 0xff
|
||||
@@ -296,7 +303,7 @@ func (pwm *pwmGroup) setPeriod(period uint64) error {
|
||||
|
||||
// Step 2 is acquiring a better top value. Clearing the equation:
|
||||
// TOP = cycles / ( (DIVINT+DIVFRAC/16) * (CSRPHCorrect+1) ) - 1
|
||||
top := 16*period/((16*whole+frac)*periodPerCycle*(1+phc)) - 1
|
||||
top := 16*period*freq/((1+phc)*1e9*(16*whole+frac)) - 1
|
||||
if top > maxTop {
|
||||
top = maxTop
|
||||
}
|
||||
@@ -400,6 +407,9 @@ func (pwm *pwmGroup) getClockDiv() (Int, frac uint8) {
|
||||
// pwmGPIOToSlice Determine the PWM channel that is attached to the specified GPIO.
|
||||
// gpio must be less than 30. Returns the PWM slice number that controls the specified GPIO.
|
||||
func pwmGPIOToSlice(gpio Pin) (slicenum uint8) {
|
||||
if is48Pin && gpio >= 32 {
|
||||
return uint8(8 + ((gpio-32)/2)%4)
|
||||
}
|
||||
return (uint8(gpio) >> 1) & 7
|
||||
}
|
||||
|
||||
@@ -104,13 +104,13 @@ func (spi SPI) Transfer(w byte) (byte, error) {
|
||||
}
|
||||
|
||||
func (spi SPI) SetBaudRate(br uint32) error {
|
||||
const freqin uint32 = 125 * MHz
|
||||
const maxBaud uint32 = 66.5 * MHz // max output frequency is 66.5MHz on rp2040. see Note page 527.
|
||||
// Find smallest prescale value which puts output frequency in range of
|
||||
// post-divide. Prescale is an even number from 2 to 254 inclusive.
|
||||
var prescale, postdiv uint32
|
||||
freq := CPUFrequency()
|
||||
for prescale = 2; prescale < 255; prescale += 2 {
|
||||
if freqin < (prescale+2)*256*br {
|
||||
if freq < (prescale+2)*256*br {
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -120,7 +120,7 @@ func (spi SPI) SetBaudRate(br uint32) error {
|
||||
// Find largest post-divide which makes output <= baudrate. Post-divide is
|
||||
// an integer in the range 1 to 256 inclusive.
|
||||
for postdiv = 256; postdiv > 1; postdiv-- {
|
||||
if freqin/(prescale*(postdiv-1)) > br {
|
||||
if freq/(prescale*(postdiv-1)) > br {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ func (uart *UART) Configure(config UARTConfig) error {
|
||||
uart.Interrupt.SetPriority(0x80)
|
||||
uart.Interrupt.Enable()
|
||||
|
||||
// setup interrupt on receive
|
||||
// Setup interrupt on receive.
|
||||
uart.Bus.UARTIMSC.Set(rp.UART0_UARTIMSC_RXIM)
|
||||
|
||||
return nil
|
||||
@@ -75,7 +75,7 @@ func (uart *UART) Configure(config UARTConfig) error {
|
||||
|
||||
// SetBaudRate sets the baudrate to be used for the UART.
|
||||
func (uart *UART) SetBaudRate(br uint32) {
|
||||
div := 8 * 125 * MHz / br
|
||||
div := 8 * CPUFrequency() / br
|
||||
|
||||
ibrd := div >> 7
|
||||
var fbrd uint32
|
||||
@@ -153,7 +153,7 @@ func initUART(uart *UART) {
|
||||
// handleInterrupt should be called from the appropriate interrupt handler for
|
||||
// this UART instance.
|
||||
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
||||
for uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_RXFE) {
|
||||
for !uart.Bus.UARTFR.HasBits(rp.UART0_UARTFR_RXFE) {
|
||||
uart.Receive(byte((uart.Bus.UARTDR.Get() & 0xFF)))
|
||||
}
|
||||
uart.Receive(byte((uart.Bus.UARTDR.Get() & 0xFF)))
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ package machine
|
||||
import (
|
||||
"device/stm32"
|
||||
|
||||
"bytes"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -41,7 +40,8 @@ func (f flashBlockDevice) WriteAt(p []byte, off int64) (n int, err error) {
|
||||
unlockFlash()
|
||||
defer lockFlash()
|
||||
|
||||
return writeFlashData(FlashDataStart()+uintptr(off), f.pad(p))
|
||||
p = flashPad(p, int(f.WriteBlockSize()))
|
||||
return writeFlashData(FlashDataStart()+uintptr(off), p)
|
||||
}
|
||||
|
||||
// Size returns the number of bytes in this block device.
|
||||
@@ -90,17 +90,6 @@ func (f flashBlockDevice) EraseBlocks(start, len int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// pad data if needed so it is long enough for correct byte alignment on writes.
|
||||
func (f flashBlockDevice) pad(p []byte) []byte {
|
||||
overflow := int64(len(p)) % f.WriteBlockSize()
|
||||
if overflow == 0 {
|
||||
return p
|
||||
}
|
||||
|
||||
padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow))
|
||||
return append(p, padding...)
|
||||
}
|
||||
|
||||
const memoryStart = 0x08000000
|
||||
|
||||
func unlockFlash() {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package descriptor
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"internal/binary"
|
||||
"internal/bytealg"
|
||||
)
|
||||
|
||||
var configurationCDCHID = [configurationTypeLen]byte{
|
||||
@@ -87,7 +87,7 @@ func FindClassHIDType(des, class []byte) (ClassHIDType, error) {
|
||||
|
||||
// search only for ClassHIDType without the ClassLength,
|
||||
// in case it has already been set.
|
||||
idx := bytes.Index(des, class[:ClassHIDTypeLen-2])
|
||||
idx := bytealg.Index(des, class[:ClassHIDTypeLen-2])
|
||||
if idx == -1 {
|
||||
return ClassHIDType{}, errNoClassHIDFound
|
||||
}
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
//go:build tinygo.riscv32 && virt
|
||||
|
||||
// Machine implementation for VirtIO targets.
|
||||
// At the moment only QEMU RISC-V is supported, but support for ARM for example
|
||||
// should not be difficult to add with a change to virtioFindDevice.
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"runtime/volatile"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const deviceName = "riscv-qemu"
|
||||
|
||||
func (p Pin) Set(high bool) {
|
||||
// no pins defined
|
||||
}
|
||||
|
||||
var rngLock sync.Mutex
|
||||
var rngDevice *virtioDevice1
|
||||
var rngBuf volatile.Register32
|
||||
|
||||
var errNoRNG = errors.New("machine: no entropy source found")
|
||||
var errNoRNGData = errors.New("machine: entropy source didn't return enough data")
|
||||
|
||||
// GetRNG returns random numbers from a VirtIO entropy source.
|
||||
// When running in QEMU, it requires adding the RNG device:
|
||||
//
|
||||
// -device virtio-rng-device
|
||||
func GetRNG() (uint32, error) {
|
||||
rngLock.Lock()
|
||||
|
||||
// Initialize the device on first use.
|
||||
if rngDevice == nil {
|
||||
// Search for an available RNG.
|
||||
rngDevice = virtioFindDevice(virtioDeviceEntropySource)
|
||||
if rngDevice == nil {
|
||||
rngLock.Unlock()
|
||||
return 0, errNoRNG
|
||||
}
|
||||
|
||||
// Initialize the device.
|
||||
rngDevice.status.Set(0) // reset device
|
||||
rngDevice.status.Set(virtioDeviceStatusAcknowledge)
|
||||
rngDevice.status.Set(virtioDeviceStatusAcknowledge | virtioDeviceStatusDriver)
|
||||
rngDevice.hostFeaturesSel.Set(0)
|
||||
rngDevice.status.Set(virtioDeviceStatusAcknowledge | virtioDeviceStatusDriver | virtioDeviceStatusDriverOk)
|
||||
rngDevice.guestPageSize.Set(4096)
|
||||
|
||||
// Configure queue, according to section 4.2.4 "Legacy interface".
|
||||
// Note: we're skipping checks for queuePFM and queueNumMax.
|
||||
rngDevice.queueSel.Set(0) // use queue 0 (the only queue)
|
||||
rngDevice.queueNum.Set(1) // use a single buffer in the queue
|
||||
rngDevice.queueAlign.Set(4096) // default alignment appears to be 4096
|
||||
rngDevice.queuePFN.Set(uint32(uintptr(unsafe.Pointer(&rngQueue))) / 4096)
|
||||
|
||||
// Configure the only buffer in the queue (but don't increment
|
||||
// rngQueue.available yet).
|
||||
rngQueue.buffers[0].address = uint64(uintptr(unsafe.Pointer(&rngBuf)))
|
||||
rngQueue.buffers[0].length = uint32(unsafe.Sizeof(rngBuf))
|
||||
rngQueue.buffers[0].flags = 2 // 2 means write-only buffer
|
||||
}
|
||||
|
||||
// Increment the available ring buffer. This doesn't actually change the
|
||||
// buffer index (it's a ring with a single entry), but the number needs to
|
||||
// be incremented otherwise the device won't recognize a new buffer.
|
||||
index := rngQueue.available.index
|
||||
rngQueue.available.index = index + 1
|
||||
rngDevice.queueNotify.Set(0) // notify the device of the 'new' (reused) buffer
|
||||
for rngQueue.used.index.Get() != index+1 {
|
||||
// Busy wait until the RNG buffer is filled.
|
||||
// A better way would be to wait for an interrupt, but since this driver
|
||||
// implementation is mostly used for testing it's good enough for now.
|
||||
}
|
||||
|
||||
// Check that we indeed got 4 bytes back.
|
||||
if rngQueue.used.ring[0].length != 4 {
|
||||
rngLock.Unlock()
|
||||
return 0, errNoRNGData
|
||||
}
|
||||
|
||||
// Read the resulting random numbers.
|
||||
result := rngBuf.Get()
|
||||
|
||||
rngLock.Unlock()
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// Implement a driver for the VirtIO entropy device.
|
||||
// https://docs.oasis-open.org/virtio/virtio/v1.2/csd01/virtio-v1.2-csd01.html
|
||||
// http://wiki.osdev.org/Virtio
|
||||
// http://www.dumais.io/index.php?article=aca38a9a2b065b24dfa1dee728062a12
|
||||
|
||||
const (
|
||||
virtioDeviceStatusAcknowledge = 1
|
||||
virtioDeviceStatusDriver = 2
|
||||
virtioDeviceStatusDriverOk = 4
|
||||
virtioDeviceStatusFeaturesOk = 8
|
||||
virtioDeviceStatusFailed = 128
|
||||
)
|
||||
|
||||
const (
|
||||
virtioDeviceReserved = iota
|
||||
virtioDeviceNetworkCard
|
||||
virtioDeviceBlockDevice
|
||||
virtioDeviceConsole
|
||||
virtioDeviceEntropySource
|
||||
// there are more device types
|
||||
)
|
||||
|
||||
// VirtIO device version 1
|
||||
type virtioDevice1 struct {
|
||||
magic volatile.Register32 // always 0x74726976
|
||||
version volatile.Register32
|
||||
deviceID volatile.Register32
|
||||
vendorID volatile.Register32
|
||||
hostFeatures volatile.Register32
|
||||
hostFeaturesSel volatile.Register32
|
||||
_ [2]uint32
|
||||
guestFeatures volatile.Register32
|
||||
guestFeaturesSel volatile.Register32
|
||||
guestPageSize volatile.Register32
|
||||
_ uint32
|
||||
queueSel volatile.Register32
|
||||
queueNumMax volatile.Register32
|
||||
queueNum volatile.Register32
|
||||
queueAlign volatile.Register32
|
||||
queuePFN volatile.Register32
|
||||
_ [3]uint32
|
||||
queueNotify volatile.Register32
|
||||
_ [3]uint32
|
||||
interruptStatus volatile.Register32
|
||||
interruptAck volatile.Register32
|
||||
_ [2]uint32
|
||||
status volatile.Register32
|
||||
}
|
||||
|
||||
// VirtIO queue, with a single buffer.
|
||||
type virtioQueue struct {
|
||||
buffers [1]struct {
|
||||
address uint64
|
||||
length uint32
|
||||
flags uint16
|
||||
next uint16
|
||||
} // 16 bytes
|
||||
|
||||
available struct {
|
||||
flags uint16
|
||||
index uint16
|
||||
ring [1]uint16
|
||||
eventIndex uint16
|
||||
} // 8 bytes
|
||||
|
||||
_ [4096 - 16*1 - 8*1]byte // padding (to align on a 4096 byte boundary)
|
||||
|
||||
used struct {
|
||||
flags uint16
|
||||
index volatile.Register16
|
||||
ring [1]struct {
|
||||
index uint32
|
||||
length uint32
|
||||
}
|
||||
availEvent uint16
|
||||
}
|
||||
}
|
||||
|
||||
func virtioFindDevice(deviceID uint32) *virtioDevice1 {
|
||||
// On RISC-V, QEMU defines 8 VirtIO devices starting at 0x10001000 and
|
||||
// repeating every 0x1000 bytes.
|
||||
// The memory map can be seen in the QEMU source code:
|
||||
// https://github.com/qemu/qemu/blob/master/hw/riscv/virt.c
|
||||
for i := 0; i < 8; i++ {
|
||||
dev := (*virtioDevice1)(unsafe.Pointer(uintptr(0x10001000 + i*0x1000)))
|
||||
if dev.magic.Get() != 0x74726976 || dev.version.Get() != 1 || dev.deviceID.Get() != deviceID {
|
||||
continue
|
||||
}
|
||||
return dev
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// A VirtIO queue needs to be page-aligned.
|
||||
//
|
||||
//go:align 4096
|
||||
var rngQueue virtioQueue
|
||||
+1
-1
Submodule src/net updated: a237059610...ca7cd08f85
@@ -307,6 +307,28 @@ func (f *File) Sync() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// Chmod changes the mode of the file to mode. If there is an error, it will be
|
||||
// of type *PathError.
|
||||
func (f *File) Chmod(mode FileMode) (err error) {
|
||||
if f.handle == nil {
|
||||
err = ErrClosed
|
||||
} else {
|
||||
err = f.chmod(mode)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Chdir changes the current working directory to the file, which must be a
|
||||
// directory. If there is an error, it will be of type *PathError.
|
||||
func (f *File) Chdir() (err error) {
|
||||
if f.handle == nil {
|
||||
err = ErrClosed
|
||||
} else {
|
||||
err = f.chdir()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// LinkError records an error during a link or symlink or rename system call and
|
||||
// the paths that caused it.
|
||||
type LinkError struct {
|
||||
|
||||
@@ -42,6 +42,12 @@ func NewFile(fd uintptr, name string) *File {
|
||||
return &File{&file{handle: stdioFileHandle(fd), name: name}}
|
||||
}
|
||||
|
||||
// Chdir changes the current working directory to the named directory.
|
||||
// If there is an error, it will be of type *PathError.
|
||||
func Chdir(dir string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
// Rename renames (moves) oldpath to newpath.
|
||||
// If newpath already exists and is not a directory, Rename replaces it.
|
||||
// OS-specific restrictions may apply when oldpath and newpath are in different directories.
|
||||
@@ -128,6 +134,10 @@ func Pipe() (r *File, w *File, err error) {
|
||||
return nil, nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func Symlink(oldname, newname string) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func Readlink(name string) (string, error) {
|
||||
return "", ErrNotImplemented
|
||||
}
|
||||
@@ -149,3 +159,11 @@ func (f *File) Truncate(size int64) (err error) {
|
||||
|
||||
return Truncate(f.name, size)
|
||||
}
|
||||
|
||||
func (f *File) chmod(mode FileMode) error {
|
||||
return ErrUnsupported
|
||||
}
|
||||
|
||||
func (f *File) chdir() error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -151,6 +151,37 @@ func (f *File) Truncate(size int64) (err error) {
|
||||
return Truncate(f.name, size)
|
||||
}
|
||||
|
||||
func (f *File) chmod(mode FileMode) error {
|
||||
if f.handle == nil {
|
||||
return ErrClosed
|
||||
}
|
||||
|
||||
longName := fixLongPath(f.name)
|
||||
e := ignoringEINTR(func() error {
|
||||
return syscall.Chmod(longName, syscallMode(mode))
|
||||
})
|
||||
if e != nil {
|
||||
return &PathError{Op: "chmod", Path: f.name, Err: e}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *File) chdir() error {
|
||||
if f.handle == nil {
|
||||
return ErrClosed
|
||||
}
|
||||
|
||||
// TODO: use syscall.Fchdir instead
|
||||
longName := fixLongPath(f.name)
|
||||
e := ignoringEINTR(func() error {
|
||||
return syscall.Chdir(longName)
|
||||
})
|
||||
if e != nil {
|
||||
return &PathError{Op: "chdir", Path: f.name, Err: e}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReadAt reads up to len(b) bytes from the File starting at the given absolute offset.
|
||||
// It returns the number of bytes read and any error encountered, possibly io.EOF.
|
||||
// At end of file, Pread returns 0, io.EOF.
|
||||
|
||||
@@ -142,3 +142,11 @@ func isWindowsNulName(name string) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *File) chmod(mode FileMode) error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
func (f *File) chdir() error {
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -271,6 +271,84 @@ func (v Value) Comparable() bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Equal reports true if v is equal to u.
|
||||
// For two invalid values, Equal will report true.
|
||||
// For an interface value, Equal will compare the value within the interface.
|
||||
// Otherwise, If the values have different types, Equal will report false.
|
||||
// Otherwise, for arrays and structs Equal will compare each element in order,
|
||||
// and report false if it finds non-equal elements.
|
||||
// During all comparisons, if values of the same type are compared,
|
||||
// and the type is not comparable, Equal will panic.
|
||||
//
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
func (v Value) Equal(u Value) bool {
|
||||
if v.Kind() == Interface {
|
||||
v = v.Elem()
|
||||
}
|
||||
if u.Kind() == Interface {
|
||||
u = u.Elem()
|
||||
}
|
||||
|
||||
if !v.IsValid() || !u.IsValid() {
|
||||
return v.IsValid() == u.IsValid()
|
||||
}
|
||||
|
||||
if v.Kind() != u.Kind() || v.Type() != u.Type() {
|
||||
return false
|
||||
}
|
||||
|
||||
// Handle each Kind directly rather than calling valueInterface
|
||||
// to avoid allocating.
|
||||
switch v.Kind() {
|
||||
default:
|
||||
panic("reflect.Value.Equal: invalid Kind")
|
||||
case Bool:
|
||||
return v.Bool() == u.Bool()
|
||||
case Int, Int8, Int16, Int32, Int64:
|
||||
return v.Int() == u.Int()
|
||||
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||
return v.Uint() == u.Uint()
|
||||
case Float32, Float64:
|
||||
return v.Float() == u.Float()
|
||||
case Complex64, Complex128:
|
||||
return v.Complex() == u.Complex()
|
||||
case String:
|
||||
return v.String() == u.String()
|
||||
case Chan, Pointer, UnsafePointer:
|
||||
return v.Pointer() == u.Pointer()
|
||||
case Array:
|
||||
// u and v have the same type so they have the same length
|
||||
vl := v.Len()
|
||||
if vl == 0 {
|
||||
// panic on [0]func()
|
||||
if !v.Type().Elem().Comparable() {
|
||||
break
|
||||
}
|
||||
return true
|
||||
}
|
||||
for i := 0; i < vl; i++ {
|
||||
if !v.Index(i).Equal(u.Index(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case Struct:
|
||||
// u and v have the same type so they have the same fields
|
||||
nf := v.NumField()
|
||||
for i := 0; i < nf; i++ {
|
||||
if !v.Field(i).Equal(u.Field(i)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case Func, Map, Slice:
|
||||
break
|
||||
}
|
||||
panic("reflect.Value.Equal: values of type " + v.Type().String() + " are not comparable")
|
||||
}
|
||||
|
||||
func (v Value) Addr() Value {
|
||||
if !v.CanAddr() {
|
||||
panic("reflect.Value.Addr of unaddressable value")
|
||||
|
||||
@@ -23,13 +23,13 @@ func fastrand() uint32 {
|
||||
return xorshift32State
|
||||
}
|
||||
|
||||
func init() {
|
||||
func initRand() {
|
||||
r, _ := hardwareRand()
|
||||
xorshift64State = uint64(r | 1) // protect against 0
|
||||
xorshift32State = uint32(xorshift64State)
|
||||
}
|
||||
|
||||
var xorshift32State uint32
|
||||
var xorshift32State uint32 = 1
|
||||
|
||||
func xorshift32(x uint32) uint32 {
|
||||
// Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs".
|
||||
@@ -49,7 +49,7 @@ func fastrand64() uint64 {
|
||||
return xorshift64State
|
||||
}
|
||||
|
||||
var xorshift64State uint64
|
||||
var xorshift64State uint64 = 1
|
||||
|
||||
// 64-bit xorshift multiply rng from http://vigna.di.unimi.it/ftp/papers/xorshift.pdf
|
||||
func xorshiftMult64(x uint64) uint64 {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"runtime/interrupt"
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
@@ -22,27 +23,27 @@ import (
|
||||
func __atomic_load_2(ptr *uint16, ordering uintptr) uint16 {
|
||||
// The LLVM docs for this say that there is a val argument after the pointer.
|
||||
// That is a typo, and the GCC docs omit it.
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
val := *ptr
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return val
|
||||
}
|
||||
|
||||
//export __atomic_store_2
|
||||
func __atomic_store_2(ptr *uint16, val uint16, ordering uintptr) {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
*ptr = val
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func doAtomicCAS16(ptr *uint16, expected, desired uint16) uint16 {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
old := *ptr
|
||||
if old == expected {
|
||||
*ptr = desired
|
||||
}
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return old
|
||||
}
|
||||
|
||||
@@ -60,10 +61,10 @@ func __atomic_compare_exchange_2(ptr, expected *uint16, desired uint16, successO
|
||||
|
||||
//go:inline
|
||||
func doAtomicSwap16(ptr *uint16, new uint16) uint16 {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
old := *ptr
|
||||
*ptr = new
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return old
|
||||
}
|
||||
|
||||
@@ -79,11 +80,11 @@ func __atomic_exchange_2(ptr *uint16, new uint16, ordering uintptr) uint16 {
|
||||
|
||||
//go:inline
|
||||
func doAtomicAdd16(ptr *uint16, value uint16) (old, new uint16) {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
old = *ptr
|
||||
new = old + value
|
||||
*ptr = new
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return old, new
|
||||
}
|
||||
|
||||
@@ -111,27 +112,27 @@ func __atomic_add_fetch_2(ptr *uint16, value uint16, ordering uintptr) uint16 {
|
||||
func __atomic_load_4(ptr *uint32, ordering uintptr) uint32 {
|
||||
// The LLVM docs for this say that there is a val argument after the pointer.
|
||||
// That is a typo, and the GCC docs omit it.
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
val := *ptr
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return val
|
||||
}
|
||||
|
||||
//export __atomic_store_4
|
||||
func __atomic_store_4(ptr *uint32, val uint32, ordering uintptr) {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
*ptr = val
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func doAtomicCAS32(ptr *uint32, expected, desired uint32) uint32 {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
old := *ptr
|
||||
if old == expected {
|
||||
*ptr = desired
|
||||
}
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return old
|
||||
}
|
||||
|
||||
@@ -149,10 +150,10 @@ func __atomic_compare_exchange_4(ptr, expected *uint32, desired uint32, successO
|
||||
|
||||
//go:inline
|
||||
func doAtomicSwap32(ptr *uint32, new uint32) uint32 {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
old := *ptr
|
||||
*ptr = new
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return old
|
||||
}
|
||||
|
||||
@@ -168,11 +169,11 @@ func __atomic_exchange_4(ptr *uint32, new uint32, ordering uintptr) uint32 {
|
||||
|
||||
//go:inline
|
||||
func doAtomicAdd32(ptr *uint32, value uint32) (old, new uint32) {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
old = *ptr
|
||||
new = old + value
|
||||
*ptr = new
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return old, new
|
||||
}
|
||||
|
||||
@@ -200,27 +201,27 @@ func __atomic_add_fetch_4(ptr *uint32, value uint32, ordering uintptr) uint32 {
|
||||
func __atomic_load_8(ptr *uint64, ordering uintptr) uint64 {
|
||||
// The LLVM docs for this say that there is a val argument after the pointer.
|
||||
// That is a typo, and the GCC docs omit it.
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
val := *ptr
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return val
|
||||
}
|
||||
|
||||
//export __atomic_store_8
|
||||
func __atomic_store_8(ptr *uint64, val uint64, ordering uintptr) {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
*ptr = val
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
}
|
||||
|
||||
//go:inline
|
||||
func doAtomicCAS64(ptr *uint64, expected, desired uint64) uint64 {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
old := *ptr
|
||||
if old == expected {
|
||||
*ptr = desired
|
||||
}
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return old
|
||||
}
|
||||
|
||||
@@ -238,10 +239,10 @@ func __atomic_compare_exchange_8(ptr, expected *uint64, desired uint64, successO
|
||||
|
||||
//go:inline
|
||||
func doAtomicSwap64(ptr *uint64, new uint64) uint64 {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
old := *ptr
|
||||
*ptr = new
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return old
|
||||
}
|
||||
|
||||
@@ -257,11 +258,11 @@ func __atomic_exchange_8(ptr *uint64, new uint64, ordering uintptr) uint64 {
|
||||
|
||||
//go:inline
|
||||
func doAtomicAdd64(ptr *uint64, value uint64) (old, new uint64) {
|
||||
mask := atomicLock()
|
||||
mask := interrupt.Disable()
|
||||
old = *ptr
|
||||
new = old + value
|
||||
*ptr = new
|
||||
atomicUnlock(mask)
|
||||
interrupt.Restore(mask)
|
||||
return old, new
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
//go:build baremetal && !tinygo.unicore
|
||||
|
||||
package runtime
|
||||
|
||||
import "runtime/interrupt"
|
||||
|
||||
func atomicLock() interrupt.State {
|
||||
return atomicLockImpl()
|
||||
}
|
||||
|
||||
func atomicUnlock(mask interrupt.State) {
|
||||
atomicUnlockImpl(mask)
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
//go:build baremetal && tinygo.unicore
|
||||
|
||||
package runtime
|
||||
|
||||
import "runtime/interrupt"
|
||||
|
||||
func atomicLock() interrupt.State {
|
||||
return interrupt.Disable()
|
||||
}
|
||||
|
||||
func atomicUnlock(mask interrupt.State) {
|
||||
interrupt.Restore(mask)
|
||||
}
|
||||
@@ -1,5 +1,14 @@
|
||||
package runtime
|
||||
|
||||
// NumCPU returns the number of logical CPUs usable by the current process.
|
||||
//
|
||||
// The set of available CPUs is checked by querying the operating system
|
||||
// at process startup. Changes to operating system CPU allocation after
|
||||
// process startup are not reflected.
|
||||
func NumCPU() int {
|
||||
return 1
|
||||
}
|
||||
|
||||
// Stub for NumCgoCall, does not return the real value
|
||||
func NumCgoCall() int {
|
||||
return 0
|
||||
|
||||
@@ -57,7 +57,6 @@ var (
|
||||
gcMallocs uint64 // total number of allocations
|
||||
gcFrees uint64 // total number of objects freed
|
||||
gcFreedBlocks uint64 // total number of freed blocks
|
||||
gcLock task.PMutex // lock to avoid race conditions on multicore systems
|
||||
)
|
||||
|
||||
// zeroSizedAlloc is just a sentinel that gets returned when allocating 0 bytes.
|
||||
@@ -318,10 +317,6 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
|
||||
runtimePanicAt(returnAddress(0), "heap alloc in interrupt")
|
||||
}
|
||||
|
||||
// Make sure there are no concurrent allocations. The heap is not currently
|
||||
// designed for concurrent alloc/GC.
|
||||
gcLock.Lock()
|
||||
|
||||
gcTotalAlloc += uint64(size)
|
||||
gcMallocs++
|
||||
|
||||
@@ -404,9 +399,6 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
|
||||
i.setState(blockStateTail)
|
||||
}
|
||||
|
||||
// We've claimed this allocation, now we can unlock the heap.
|
||||
gcLock.Unlock()
|
||||
|
||||
// Return a pointer to this allocation.
|
||||
pointer := thisAlloc.pointer()
|
||||
if preciseHeap {
|
||||
@@ -452,9 +444,7 @@ func free(ptr unsafe.Pointer) {
|
||||
|
||||
// GC performs a garbage collection cycle.
|
||||
func GC() {
|
||||
gcLock.Lock()
|
||||
runGC()
|
||||
gcLock.Unlock()
|
||||
}
|
||||
|
||||
// runGC performs a garbage collection cycle. It is the internal implementation
|
||||
@@ -466,7 +456,8 @@ func runGC() (freeBytes uintptr) {
|
||||
}
|
||||
|
||||
// Mark phase: mark all reachable objects, recursively.
|
||||
gcMarkReachable()
|
||||
markStack()
|
||||
findGlobals(markRoots)
|
||||
|
||||
if baremetal && hasScheduler {
|
||||
// Channel operations in interrupts may move task pointers around while we are marking.
|
||||
@@ -723,7 +714,6 @@ func dumpHeap() {
|
||||
// The returned memory statistics are up to date as of the
|
||||
// call to ReadMemStats. This would not do GC implicitly for you.
|
||||
func ReadMemStats(m *MemStats) {
|
||||
gcLock.Lock()
|
||||
m.HeapIdle = 0
|
||||
m.HeapInuse = 0
|
||||
for block := gcBlock(0); block < endBlock; block++ {
|
||||
@@ -743,7 +733,6 @@ func ReadMemStats(m *MemStats) {
|
||||
m.Sys = uint64(heapEnd - heapStart)
|
||||
m.HeapAlloc = (gcTotalBlocks - gcFreedBlocks) * uint64(bytesPerBlock)
|
||||
m.Alloc = m.HeapAlloc
|
||||
gcLock.Unlock()
|
||||
}
|
||||
|
||||
func SetFinalizer(obj interface{}, finalizer interface{}) {
|
||||
|
||||
@@ -8,11 +8,6 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func gcMarkReachable() {
|
||||
markStack()
|
||||
findGlobals(markRoots)
|
||||
}
|
||||
|
||||
//go:extern runtime.stackChainStart
|
||||
var stackChainStart *stackChainObject
|
||||
|
||||
|
||||
@@ -1,14 +1,9 @@
|
||||
//go:build (gc.conservative || gc.precise) && !tinygo.wasm && !scheduler.threads && !scheduler.cores
|
||||
//go:build (gc.conservative || gc.precise) && !tinygo.wasm
|
||||
|
||||
package runtime
|
||||
|
||||
import "internal/task"
|
||||
|
||||
func gcMarkReachable() {
|
||||
markStack()
|
||||
findGlobals(markRoots)
|
||||
}
|
||||
|
||||
// markStack marks all root pointers found on the stack.
|
||||
//
|
||||
// This implementation is conservative and relies on the stack top (provided by
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user