mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 11:07:46 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d74a132735 |
@@ -27,7 +27,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.20'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v3
|
||||
@@ -108,7 +108,7 @@ jobs:
|
||||
# We're doing the former here, to keep artifact uploads fast.
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: darwin-amd64-double-zipped
|
||||
name: release-double-zipped
|
||||
path: build/tinygo.darwin-amd64.tar.gz
|
||||
- name: Smoke tests
|
||||
shell: bash
|
||||
@@ -126,7 +126,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.20'
|
||||
cache: true
|
||||
- name: Build TinyGo
|
||||
run: go install
|
||||
|
||||
@@ -18,7 +18,7 @@ jobs:
|
||||
# statically linked binary.
|
||||
runs-on: ubuntu-latest
|
||||
container:
|
||||
image: golang:1.21-alpine
|
||||
image: golang:1.20-alpine
|
||||
steps:
|
||||
- name: Install apk dependencies
|
||||
# tar: needed for actions/cache@v3
|
||||
@@ -135,7 +135,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.20'
|
||||
cache: true
|
||||
- name: Install wasmtime
|
||||
run: |
|
||||
@@ -153,7 +153,6 @@ jobs:
|
||||
tar -C ~/lib -xf tinygo.linux-amd64.tar.gz
|
||||
ln -s ~/lib/tinygo/bin/tinygo ~/go/bin/tinygo
|
||||
- run: make tinygo-test-wasi-fast
|
||||
- run: make tinygo-test-wasip1-fast
|
||||
- run: make smoketest
|
||||
assert-test-linux:
|
||||
# Run all tests that can run on Linux, with LLVM assertions enabled to catch
|
||||
@@ -178,12 +177,12 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.20'
|
||||
cache: true
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '16'
|
||||
node-version: '14'
|
||||
- name: Install wasmtime
|
||||
run: |
|
||||
mkdir -p $HOME/.wasmtime $HOME/.wasmtime/bin
|
||||
@@ -291,7 +290,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.20'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v3
|
||||
@@ -408,7 +407,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.20'
|
||||
cache: true
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v3
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
name: Binary size difference
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
sizediff:
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
# Prepare, install tools
|
||||
- name: Add GOBIN to $PATH
|
||||
run: |
|
||||
echo "$HOME/go/bin" >> $GITHUB_PATH
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # fetch all history (no sparse checkout)
|
||||
submodules: true
|
||||
- name: Install apt dependencies
|
||||
run: |
|
||||
echo 'deb https://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main' | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends -y \
|
||||
llvm-15-dev \
|
||||
clang-15 \
|
||||
libclang-15-dev \
|
||||
lld-15
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache@v3
|
||||
id: cache-llvm-source
|
||||
with:
|
||||
key: llvm-source-15-sizediff-v1
|
||||
path: |
|
||||
llvm-project/compiler-rt
|
||||
- name: Download LLVM source
|
||||
if: steps.cache-llvm-source.outputs.cache-hit != 'true'
|
||||
run: make llvm-source
|
||||
- name: Cache Go
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
key: go-cache-linux-sizediff-v1-${{ hashFiles('go.mod') }}
|
||||
path: |
|
||||
~/.cache/go-build
|
||||
~/go/pkg/mod
|
||||
- run: make gen-device -j4
|
||||
- name: Download drivers repo
|
||||
run: git clone https://github.com/tinygo-org/drivers.git
|
||||
- name: Save HEAD
|
||||
run: git branch github-actions-saved-HEAD HEAD
|
||||
|
||||
# Compute sizes for the dev branch
|
||||
- name: Checkout dev branch
|
||||
run: git checkout --no-recurse-submodules `git merge-base HEAD origin/dev`
|
||||
- name: Build tinygo binary for the dev branch
|
||||
run: go install
|
||||
- name: Determine binary sizes on the dev branch
|
||||
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-dev.txt)
|
||||
|
||||
# Compute sizes for the PR branch
|
||||
- name: Checkout PR branch
|
||||
run: git checkout --no-recurse-submodules github-actions-saved-HEAD
|
||||
- name: Build tinygo binary for the PR branch
|
||||
run: go install
|
||||
- name: Determine binary sizes on the PR branch
|
||||
run: (cd drivers; make smoke-test XTENSA=0 | tee sizes-pr.txt)
|
||||
|
||||
# Create comment
|
||||
# TODO: add a summary, something like:
|
||||
# - overall size difference (percent)
|
||||
# - number of binaries that grew / shrank / remained the same
|
||||
# - don't show the full diff when no binaries changed
|
||||
- name: Calculate size diff
|
||||
run: ./tools/sizediff drivers/sizes-dev.txt drivers/sizes-pr.txt | tee sizediff.txt
|
||||
- name: Create comment
|
||||
run: |
|
||||
echo "Size difference with the dev branch:" > comment.txt
|
||||
echo "<details><summary>Binary size difference</summary>" >> comment.txt
|
||||
echo "<pre>" >> comment.txt
|
||||
cat sizediff.txt >> comment.txt
|
||||
echo "</pre></details>" >> comment.txt
|
||||
- name: Comment contents
|
||||
run: cat comment.txt
|
||||
- name: Add comment
|
||||
if: ${{ github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name }}
|
||||
uses: thollander/actions-comment-pull-request@v2.3.1
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
filePath: comment.txt
|
||||
comment_tag: sizediff
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.20'
|
||||
cache: true
|
||||
- name: Restore cached LLVM source
|
||||
uses: actions/cache/restore@v3
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
# We're doing the former here, to keep artifact uploads fast.
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: windows-amd64-double-zipped
|
||||
name: release-double-zipped
|
||||
path: build/release/release.zip
|
||||
|
||||
smoke-test-windows:
|
||||
@@ -143,12 +143,12 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.20'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: windows-amd64-double-zipped
|
||||
name: release-double-zipped
|
||||
path: build/
|
||||
- name: Unzip TinyGo build
|
||||
shell: bash
|
||||
@@ -173,12 +173,12 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.20'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: windows-amd64-double-zipped
|
||||
name: release-double-zipped
|
||||
path: build/
|
||||
- name: Unzip TinyGo build
|
||||
shell: bash
|
||||
@@ -209,12 +209,12 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v3
|
||||
with:
|
||||
go-version: '1.21'
|
||||
go-version: '1.20'
|
||||
cache: true
|
||||
- name: Download TinyGo build
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: windows-amd64-double-zipped
|
||||
name: release-double-zipped
|
||||
path: build/
|
||||
- name: Unzip TinyGo build
|
||||
shell: bash
|
||||
|
||||
@@ -31,6 +31,3 @@
|
||||
[submodule "lib/macos-minimal-sdk"]
|
||||
path = lib/macos-minimal-sdk
|
||||
url = https://github.com/aykevl/macos-minimal-sdk.git
|
||||
[submodule "lib/renesas-svd"]
|
||||
path = lib/renesas-svd
|
||||
url = https://github.com/tinygo-org/renesas-svd.git
|
||||
|
||||
-208
@@ -1,211 +1,3 @@
|
||||
0.29.0
|
||||
---
|
||||
|
||||
* **general**
|
||||
- Go 1.21 support
|
||||
- use https for renesas submodule #3856
|
||||
- ci: rename release-double-zipped to something more useful
|
||||
- ci: update Node.js from version 14 to version 16
|
||||
- ci: switch GH actions builds to use Go 1.21 final release
|
||||
- docker: update clang to version 15
|
||||
- docker: use Go 1.21 for Docker dev container build
|
||||
- `main`: add target JSON file in `tinygo info` output
|
||||
- `main`: improve detection of filesystems
|
||||
- `main`: use `go env` instead of doing all detection manually
|
||||
- make: add make task to generate Renesas device wrappers
|
||||
- make: add task to check NodeJS version before running tests
|
||||
- add submodule for Renesas SVD file mirror repo
|
||||
- update to go-serial package v1.6.0
|
||||
- `testing`: add Testing function
|
||||
- `tools/gen-device-svd`: small changes needed for Renesas MCUs
|
||||
* **compiler**
|
||||
- `builder`: update message for max supported Go version
|
||||
- `compiler,reflect`: NumMethods reports exported methods only
|
||||
- `compiler`: add compiler-rt and wasm symbols to table
|
||||
- `compiler`: add compiler-rt to wasm.json
|
||||
- `compiler`: add min and max builtin support
|
||||
- `compiler`: implement clear builtin for maps
|
||||
- `compiler`: implement clear builtin for slices
|
||||
- `compiler`: improve panic message when a runtime call is unavailable
|
||||
- `compiler`: update .ll test output
|
||||
- `loader`: merge go.env file which is now required starting in Go 1.21 to correctly get required packages
|
||||
* **standard library**
|
||||
- `os`: define ErrNoDeadline
|
||||
- `reflect`: Add FieldByNameFunc
|
||||
- `reflect`: add SetZero
|
||||
- `reflect`: fix iterating over maps with interface{} keys
|
||||
- `reflect`: implement Value.Grow
|
||||
- `reflect`: remove unecessary heap allocations
|
||||
- `reflect`: use .key() instead of a type assert
|
||||
- `sync`: add implementation from upstream Go for OnceFunc, OnceValue, and OnceValues
|
||||
* **targets**
|
||||
- `machine`: UART refactor (#3832)
|
||||
- `machine/avr`: pin change interrupt
|
||||
- `machine/macropad_rp2040`: add machine.BUTTON
|
||||
- `machine/nrf`: add I2C timeout
|
||||
- `machine/nrf`: wait for stop condition after reading from the I2C bus
|
||||
- `machine/nRF52`: set SPI TX/RX lengths even data is empty. Fixes #3868 (#3877)
|
||||
- `machine/rp2040`: add missing suffix to CMD_READ_STATUS
|
||||
- `machine/rp2040`: add NoPin support
|
||||
- `machine/rp2040`: move flash related functions into separate file from C imports for correct - LSP. Fixes #3852
|
||||
- `machine/rp2040`: wait for 1000 us after flash reset to avoid issues with busy USB bus
|
||||
- `machine/samd51,rp2040,nrf528xx,stm32`: implement watchdog
|
||||
- `machine/samd51`: fix i2cTimeout was decreasing due to cache activation
|
||||
- `machine/usb`: Add support for HID Keyboard LEDs
|
||||
- `machine/usb`: allow USB Endpoint settings to be changed externally
|
||||
- `machine/usb`: refactor endpoint configuration
|
||||
- `machine/usb`: remove usbDescriptorConfig
|
||||
- `machine/usb/hid,joystick`: fix hidreport (3) (#3802)
|
||||
- `machine/usb/hid`: add RxHandler interface
|
||||
- `machine/usb/hid`: rename Handler() to TxHandler()
|
||||
- `wasi`: allow zero inodes when reading directories
|
||||
- `wasm`: add support for GOOS=wasip1
|
||||
- `wasm`: fix functions exported through //export
|
||||
- `wasm`: remove i64 workaround, use BigInt instead
|
||||
- `example`: adjust time offset
|
||||
- `example`: simplify pininterrupt
|
||||
* **boards**
|
||||
- `targets`: add AKIZUKI DENSHI AE-RP2040
|
||||
- `targets`: adding new uf2 target for PCA10056 (#3765)
|
||||
|
||||
|
||||
0.28.0
|
||||
---
|
||||
|
||||
* **general**
|
||||
- fix parallelism in the compiler on Windows by building LLVM with thread support
|
||||
- support qemu-user debugging
|
||||
- make target JSON msd-volume-name an array
|
||||
- print source location when a panic happens in -monitor
|
||||
- `test`: don't print `ok` for a successful compile-only
|
||||
* **compiler**
|
||||
- `builder`: remove non-ThinLTO build mode
|
||||
- `builder`: fail earlier if Go is not available
|
||||
- `builder`: improve `-size=full` in a number of ways
|
||||
- `builder`: implement Nordic DFU file writer in Go
|
||||
- `cgo`: allow `LDFLAGS: --export=...`
|
||||
- `compiler`: support recursive slice types
|
||||
- `compiler`: zero struct padding during map operations
|
||||
- `compiler`: add llvm.ident metadata
|
||||
- `compiler`: remove `unsafe.Pointer(uintptr(v) + idx)` optimization (use `unsafe.Add` instead)
|
||||
- `compiler`: add debug info to `//go:embed` data structures for better `-size` output
|
||||
- `compiler`: add debug info to string constants
|
||||
- `compiler`: fix a minor race condition
|
||||
- `compiler`: emit correct alignment in debug info for global variables
|
||||
- `compiler`: correctly generate reflect data for local named types
|
||||
- `compiler`: add alloc attributes to `runtime.alloc`, reducing flash usage slightly
|
||||
- `compiler`: for interface maps, use the original named type if available
|
||||
- `compiler`: implement most math/bits functions as LLVM intrinsics
|
||||
- `compiler`: ensure all defers have been seen before creating rundefers
|
||||
* **standard library**
|
||||
- `internal/task`: disallow blocking inside an interrupt
|
||||
- `machine`: add `CPUReset`
|
||||
- `machine/usb/hid`: add MediaKey support
|
||||
- `machine/usb/hid/joystick`: move joystick under HID
|
||||
- `machine/usb/hid/joystick`: allow joystick settings override
|
||||
- `machine/usb/hid/joystick`: handle case where we cannot find the correct HID descriptor
|
||||
- `machine/usb/hid/mouse`: add support for mouse back and forward
|
||||
- `machine/usb`: add ability to override default VID, PID, manufacturer name, and product name
|
||||
- `net`: added missing `TCPAddr` and `UDPAddr` implementations
|
||||
- `os`: add IsTimeout function
|
||||
- `os`: fix resource leak in `(*File).Close`
|
||||
- `os`: add `(*File).Sync`
|
||||
- `os`: implement `(*File).ReadDir` for wasi
|
||||
- `os`: implement `(*File).WriteAt`
|
||||
- `reflect`: make sure null bytes are supported in tags
|
||||
- `reflect`: refactor this package to enable many new features
|
||||
- `reflect`: add map type methods: `Elem` and `Key`
|
||||
- `reflect`: add map methods: `MapIndex`, `MapRange`/`MapIter`, `SetMapIndex`, `MakeMap`, `MapKeys`
|
||||
- `reflect`: add slice methods: `Append`, `MakeSlice`, `Slice`, `Slice3`, `Copy`, `Bytes`, `SetLen`
|
||||
- `reflect`: add misc methods: `Zero`, `Addr`, `UnsafeAddr`, `OverflowFloat`, `OverflowInt`, `OverflowUint`, `SetBytes`, `Convert`, `CanInt`, `CanFloat`, `CanComplex`, `Comparable`
|
||||
- `reflect`: add type methods: `String`, `PkgPath`, `FieldByName`, `FieldByIndex`, `NumMethod`
|
||||
- `reflect`: add stubs for `Type.Method`, `CanConvert`, `ArrayOf`, `StructOf`, `MapOf`
|
||||
- `reflect`: add stubs for channel select routines/types
|
||||
- `reflect`: allow nil rawType to call Kind()
|
||||
- `reflect`: ensure all ValueError panics have Kind fields
|
||||
- `reflect`: add support for named types
|
||||
- `reflect`: improve `Value.String()`
|
||||
- `reflect`: set `Index` and `PkgPath` field in `Type.Field`
|
||||
- `reflect`: `Type.AssignableTo`: you can assign anything to `interface{}`
|
||||
- `reflect`: add type check to `Value.Field`
|
||||
- `reflect`: let `TypeOf(nil)` return nil
|
||||
- `reflect`: move `StructField.Anonymous` field to match upstream location
|
||||
- `reflect`: add `UnsafePointer` for Func types
|
||||
- `reflect`: `MapIter.Next` needs to allocate new keys/values every time
|
||||
- `reflect`: fix `IsNil` for interfaces
|
||||
- `reflect`: fix `Type.Name` to return an empty string for non-named types
|
||||
- `reflect`: add `VisibleFields`
|
||||
- `reflect`: properly handle embedded structs
|
||||
- `reflect`: make sure `PointerTo` works for named types
|
||||
- `reflect`: `Set`: convert non-interface to interface
|
||||
- `reflect`: `Set`: fix direction of assignment check
|
||||
- `reflect`: support channel directions
|
||||
- `reflect`: print struct tags in Type.String()
|
||||
- `reflect`: properly handle read-only values
|
||||
- `runtime`: allow custom-gc SetFinalizer and clarify KeepAlive
|
||||
- `runtime`: implement KeepAlive using inline assembly
|
||||
- `runtime`: check for heap allocations inside interrupts
|
||||
- `runtime`: properly turn pointer into empty interface when hashing
|
||||
- `runtime`: improve map size hint usage
|
||||
- `runtime`: zero map key/value on deletion to so GC doesn't see them
|
||||
- `runtime`: print the address where a panic happened
|
||||
- `runtime/debug`: stub `SetGCPercent`, `BuildInfo.Settings`
|
||||
- `runtime/metrics`: add this package as a stub
|
||||
- `syscall`: `Stat_t` timespec fields are Atimespec on darwin
|
||||
- `syscall`: add `Timespec.Unix()` for wasi
|
||||
- `syscall`: add fsync using libc
|
||||
- `testing`: support -test.count
|
||||
- `testing`: make test output unbuffered when verbose
|
||||
- `testing`: add -test.skip
|
||||
- `testing`: move runtime.GC() call to runN to match upstream
|
||||
- `testing`: add -test.shuffle to order randomize test and benchmark order
|
||||
* **targets**
|
||||
- `arm64`: fix register save/restore to include vector registers
|
||||
- `attiny1616`: add support for this chip
|
||||
- `cortexm`: refactor EnableInterrupts and DisableInterrupts to avoid `arm.AsmFull`
|
||||
- `cortexm`: enable functions in RAM for go & cgo
|
||||
- `cortexm`: convert SystemStack from `AsmFull` to C inline assembly
|
||||
- `cortexm`: fix crash due to wrong stack size offset
|
||||
- `nrf`: samd21, stm32: add flash API
|
||||
- `nrf`: fix memory issue in ADC read
|
||||
- `nrf`: new peripheral type for nrf528xx chips
|
||||
- `nrf`: implement target mode
|
||||
- `nrf`: improve ADC and add oversampling, longer sample time, and reference voltage
|
||||
- `rp2040`: change calling order for device enumeration fix to do first
|
||||
- `rp2040`: rtc delayed interrupt
|
||||
- `rp2040`: provide better errors for invalid pins on I2C and SPI
|
||||
- `rp2040`: change uart to allow for a single pin
|
||||
- `rp2040`: implement Flash interface
|
||||
- `rp2040`: remove SPI `DataBits` property
|
||||
- `rp2040`: unify all linker scripts using LDFLAGS
|
||||
- `rp2040`: remove SPI deadline for improved performance
|
||||
- `rp2040`: use 4MHz as default frequency for SPI
|
||||
- `rp2040`: implement target mode
|
||||
- `rp2040`: use DMA for send-only SPI transfers
|
||||
- `samd21`: rearrange switch case for get pin cfg
|
||||
- `samd21`: fix issue with WS2812 driver by making pin accesses faster
|
||||
- `samd51`: enable CMCC cache for greatly improved performance
|
||||
- `samd51`: remove extra BK0RDY clear
|
||||
- `samd51`: implement Flash interface
|
||||
- `samd51`: use correct SPI frequency
|
||||
- `samd51`: remove extra BK0RDY clear
|
||||
- `samd51`: fix ADC multisampling
|
||||
- `wasi`: allow users to set the `runtime_memhash_tsip` or `runtime_memhash_fnv` build tags
|
||||
- `wasi`: set `WASMTIME_BACKTRACE_DETAILS` when running in wasmtime.
|
||||
- `wasm`: implement the `//go:wasmimport` directive
|
||||
* **boards**
|
||||
- `gameboy-advance`: switch to use register definitions in device/gba
|
||||
- `gameboy-advance`: rename display and make pointer receivers
|
||||
- `gopher-badge`: Added Gopher Badge support
|
||||
- `lorae5`: add needed definition for UART2
|
||||
- `lorae5`: correct mapping for I2C bus, add pin mapping to enable power
|
||||
- `pinetime`: update the target file (rename from pinetime-devkit0)
|
||||
- `qtpy`: fix bad pin assignment
|
||||
- `wioterminal`: fix pin definition of BCM13
|
||||
- `xiao`: Pins D4 & D5 are I2C1. Use pins D2 & D3 for I2C0.
|
||||
- `xiao`: add DefaultUART
|
||||
|
||||
|
||||
0.27.0
|
||||
---
|
||||
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
# tinygo-llvm stage obtains the llvm source for TinyGo
|
||||
FROM golang:1.21 AS tinygo-llvm
|
||||
FROM golang:1.20 AS tinygo-llvm
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y apt-utils make cmake clang-15 ninja-build
|
||||
apt-get install -y apt-utils make cmake clang-11 ninja-build
|
||||
|
||||
COPY ./Makefile /tinygo/Makefile
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Copyright (c) 2018-2023 The TinyGo Authors. All rights reserved.
|
||||
Copyright (c) 2018-2022 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-2022 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.
|
||||
|
||||
@@ -232,10 +232,6 @@ gen-device-rp: build/gen-device-svd
|
||||
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/RaspberryPi lib/cmsis-svd/data/RaspberryPi/ src/device/rp/
|
||||
GO111MODULE=off $(GO) fmt ./src/device/rp
|
||||
|
||||
gen-device-renesas: build/gen-device-svd
|
||||
./build/gen-device-svd -source=https://github.com/tinygo-org/renesas-svd lib/renesas-svd/ src/device/renesas/
|
||||
GO111MODULE=off $(GO) fmt ./src/device/renesas
|
||||
|
||||
# Get LLVM sources.
|
||||
$(LLVM_PROJECTDIR)/llvm:
|
||||
git clone -b xtensa_release_15.x --depth=1 https://github.com/espressif/llvm-project $(LLVM_PROJECTDIR)
|
||||
@@ -267,22 +263,12 @@ lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
|
||||
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
|
||||
cd lib/wasi-libc && make -j4 EXTRA_CFLAGS="-O2 -g -DNDEBUG -mnontrapping-fptoint -msign-ext" MALLOC_IMPL=none CC=$(CLANG) AR=$(LLVM_AR) NM=$(LLVM_NM)
|
||||
|
||||
# Check for Node.js used during WASM tests.
|
||||
NODEJS_VERSION := $(word 1,$(subst ., ,$(shell node -v | cut -c 2-)))
|
||||
MIN_NODEJS_VERSION=16
|
||||
|
||||
.PHONY: check-nodejs-version
|
||||
check-nodejs-version:
|
||||
ifeq (, $(shell which node))
|
||||
@echo "Install NodeJS version 16+ to run tests."; exit 1;
|
||||
endif
|
||||
@if [ $(NODEJS_VERSION) -lt $(MIN_NODEJS_VERSION) ]; then echo "Install NodeJS version 16+ to run tests."; exit 1; fi
|
||||
|
||||
# Build the Go compiler.
|
||||
tinygo:
|
||||
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " make llvm-source"; echo " make $(LLVM_BUILDDIR)"; exit 1; fi
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GOENVFLAGS) $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags "byollvm osusergo" -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
|
||||
test: wasi-libc check-nodejs-version
|
||||
test: wasi-libc
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags "byollvm osusergo" ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||
|
||||
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
|
||||
@@ -427,12 +413,8 @@ tinygo-bench-fast:
|
||||
# Same thing, except for wasi rather than the current platform.
|
||||
tinygo-test-wasi:
|
||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||
tinygo-test-wasip1:
|
||||
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW) ./tests/runtime_wasi
|
||||
tinygo-test-wasi-fast:
|
||||
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||
tinygo-test-wasip1-fast:
|
||||
GOOS=wasip1 GOARCH=wasm $(TINYGO) test $(TEST_PACKAGES_FAST) ./tests/runtime_wasi
|
||||
tinygo-bench-wasi:
|
||||
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
|
||||
tinygo-bench-wasi-fast:
|
||||
@@ -496,16 +478,10 @@ smoketest:
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/test
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/time-offset
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-mouse
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/hid-keyboard
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/i2c-target
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/watchdog
|
||||
@$(MD5SUM) test.hex
|
||||
# test simulated boards on play.tinygo.org
|
||||
ifneq ($(WASM), 0)
|
||||
$(TINYGO) build -size short -o test.wasm -tags=arduino examples/blinky1
|
||||
@@ -550,8 +526,6 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10059 examples/blinky2
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=bluemicro840 examples/blinky2
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-m0 examples/blinky1
|
||||
@@ -588,7 +562,7 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=particle-xenon examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pinetime examples/blinky1
|
||||
$(TINYGO) build -size short -o test.hex -target=pinetime-devkit0 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=x9pro examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -664,8 +638,6 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=gopher-badge examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=ae-rp2040 examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
# test pwm
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -730,8 +702,6 @@ endif
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-nano examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=attiny1616 examples/empty
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1
|
||||
@@ -745,8 +715,6 @@ ifneq ($(XTENSA), 0)
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target m5stack examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target m5stick-c examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target mch2022 examples/serial
|
||||
@$(MD5SUM) test.bin
|
||||
endif
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
|
||||
[](https://github.com/tinygo-org/tinygo/actions/workflows/linux.yml) [](https://github.com/tinygo-org/tinygo/actions/workflows/build-macos.yml) [](https://github.com/tinygo-org/tinygo/actions/workflows/windows.yml) [](https://github.com/tinygo-org/tinygo/actions/workflows/docker.yml) [](https://circleci.com/gh/tinygo-org/tinygo/tree/dev)
|
||||
|
||||
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (wasm/wasi), and command-line tools.
|
||||
TinyGo is a Go compiler intended for use in small places such as microcontrollers, WebAssembly (Wasm), and command-line tools.
|
||||
|
||||
It reuses libraries used by the [Go language tools](https://golang.org/pkg/go/) alongside [LLVM](http://llvm.org) to provide an alternative way to compile programs written in the Go programming language.
|
||||
|
||||
## Embedded
|
||||
|
||||
Here is an example program that blinks the built-in LED when run directly on any supported board with onboard LED:
|
||||
|
||||
```go
|
||||
@@ -37,62 +35,115 @@ The above program can be compiled and run without modification on an Arduino Uno
|
||||
tinygo flash -target arduino examples/blinky1
|
||||
```
|
||||
|
||||
## WebAssembly
|
||||
|
||||
TinyGo is very useful for compiling programs both for use in browsers (WASM) as well as for use on servers and other edge devices (WASI).
|
||||
|
||||
TinyGo programs can run in Fastly Compute@Edge (https://developer.fastly.com/learning/compute/go/), Fermyon Spin (https://developer.fermyon.com/spin/go-components), wazero (https://wazero.io/languages/tinygo/) and many other WebAssembly runtimes.
|
||||
|
||||
Here is a small TinyGo program for use by a WASI host application:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
//go:wasm-module yourmodulename
|
||||
//export add
|
||||
func add(x, y uint32) uint32 {
|
||||
return x + y
|
||||
}
|
||||
|
||||
// main is required for the `wasi` target, even if it isn't used.
|
||||
func main() {}
|
||||
```
|
||||
|
||||
This compiles the above TinyGo program for use on any WASI runtime:
|
||||
|
||||
```shell
|
||||
tinygo build -o main.wasm -target=wasi main.go
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
See the [getting started instructions](https://tinygo.org/getting-started/) for information on how to install TinyGo, as well as how to run the TinyGo compiler using our Docker container.
|
||||
|
||||
## Supported targets
|
||||
## Supported boards/targets
|
||||
|
||||
### Embedded
|
||||
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
||||
|
||||
You can compile TinyGo programs for over 94 different microcontroller boards.
|
||||
The following 94 microcontroller boards are currently supported:
|
||||
|
||||
For more information, please see https://tinygo.org/docs/reference/microcontrollers/
|
||||
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||
* [Adafruit CLUE](https://www.adafruit.com/product/4500)
|
||||
* [Adafruit Feather M0](https://www.adafruit.com/product/2772)
|
||||
* [Adafruit Feather M0 Express](https://www.adafruit.com/product/3403)
|
||||
* [Adafruit Feather M4](https://www.adafruit.com/product/3857)
|
||||
* [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759)
|
||||
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
|
||||
* [Adafruit Feather nRF52840 Sense](https://www.adafruit.com/product/4516)
|
||||
* [Adafruit Feather RP2040](https://www.adafruit.com/product/4884)
|
||||
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
|
||||
* [Adafruit Grand Central M4](https://www.adafruit.com/product/4064)
|
||||
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
|
||||
* [Adafruit ItsyBitsy M4](https://www.adafruit.com/product/3800)
|
||||
* [Adafruit ItsyBitsy nRF52840](https://www.adafruit.com/product/4481)
|
||||
* [Adafruit KB2040](https://www.adafruit.com/product/5302)
|
||||
* [Adafruit MacroPad RP2040](https://www.adafruit.com/product/5100)
|
||||
* [Adafruit Matrix Portal M4](https://www.adafruit.com/product/4745)
|
||||
* [Adafruit Metro M4 Express Airlift](https://www.adafruit.com/product/4000)
|
||||
* [Adafruit PyBadge](https://www.adafruit.com/product/4200)
|
||||
* [Adafruit PyGamer](https://www.adafruit.com/product/4242)
|
||||
* [Adafruit PyPortal](https://www.adafruit.com/product/4116)
|
||||
* [Adafruit QT Py](https://www.adafruit.com/product/4600)
|
||||
* [Adafruit QT Py RP2040](https://www.adafruit.com/product/4900)
|
||||
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
|
||||
* [Adafruit Trinkey QT2040](https://adafruit.com/product/5056)
|
||||
* [Arduino Mega 1280](https://www.arduino.cc/en/Main/arduinoBoardMega/)
|
||||
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
|
||||
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
|
||||
* [Arduino MKR WiFi 1010](https://store.arduino.cc/usa/mkr-wifi-1010)
|
||||
* [Arduino Nano](https://store.arduino.cc/arduino-nano)
|
||||
* [Arduino Nano 33 BLE](https://store.arduino.cc/nano-33-ble)
|
||||
* [Arduino Nano 33 BLE Sense](https://store.arduino.cc/nano-33-ble-sense)
|
||||
* [Arduino Nano 33 IoT](https://store.arduino.cc/nano-33-iot)
|
||||
* [Arduino Nano RP2040 Connect](https://store.arduino.cc/nano-rp2040-connect)
|
||||
* [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3)
|
||||
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
|
||||
* [BBC micro:bit](https://microbit.org/)
|
||||
* [BBC micro:bit v2](https://microbit.org/new-microbit/)
|
||||
* [blues wireless Swan](https://blues.io/products/swan/)
|
||||
* [Digispark](http://digistump.com/products/1)
|
||||
* [Dragino LoRaWAN GPS Tracker LGT-92](http://www.dragino.com/products/lora-lorawan-end-node/item/142-lgt-92.html)
|
||||
* [ESP32 - Core board](https://www.espressif.com/en/products/socs/esp32)
|
||||
* [ESP32 - mini32](https://www.espressif.com/en/products/socs/esp32)
|
||||
* [ESP32-C3-12f](https://www.espressif.com/en/products/socs/esp32-c3)
|
||||
* [ESP8266 - d1mini](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [ESP8266 - NodeMCU](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
|
||||
* [iLabs Challenger RP2040 LoRa](https://ilabs.se/product/challenger-rp2040-lora/)
|
||||
* [M5Stack](https://docs.m5stack.com/en/core/basic)
|
||||
* [M5Stack Core2](https://shop.m5stack.com/products/m5stack-core2-esp32-iot-development-kit)
|
||||
* [M5Stamp C3](https://docs.m5stack.com/en/core/stamp_c3)
|
||||
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
|
||||
* [Makerdiary nRF52840-MDK USB Dongle](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
|
||||
* [MCH2022 badge](https://badge.team/docs/badges/mch2022/)
|
||||
* [Microchip SAM E54 Xplained Pro](https://www.microchip.com/developmenttools/productdetails/atsame54-xpro)
|
||||
* [nice!nano](https://docs.nicekeyboards.com/#/nice!nano/)
|
||||
* [Nintendo Switch](https://www.nintendo.com/switch/)
|
||||
* [Nordic Semiconductor PCA10031](https://www.nordicsemi.com/eng/Products/nRF51-Dongle)
|
||||
* [Nordic Semiconductor PCA10040](https://www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF52-DK)
|
||||
* [Nordic Semiconductor PCA10056](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
|
||||
* [Nordic Semiconductor pca10059](https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-Dongle)
|
||||
* [Particle Argon](https://docs.particle.io/datasheets/wi-fi/argon-datasheet/)
|
||||
* [Particle Boron](https://docs.particle.io/datasheets/cellular/boron-datasheet/)
|
||||
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
|
||||
* [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/)
|
||||
* [Pimoroni Badger2040](https://shop.pimoroni.com/products/badger-2040)
|
||||
* [Pimoroni Tufty2040](https://shop.pimoroni.com/products/tufty-2040)
|
||||
* [PineTime DevKit](https://www.pine64.org/pinetime/)
|
||||
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
|
||||
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
|
||||
* [PJRC Teensy 4.1](https://www.pjrc.com/store/teensy41.html)
|
||||
* [ProductivityOpen P1AM-100](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html)
|
||||
* [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)
|
||||
* [Raytac MDBT50Q-RX Dongle (with TinyUF2 bootloader)](https://www.adafruit.com/product/5199)
|
||||
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
|
||||
* [Seeed XIAO BLE](https://www.seeedstudio.com/Seeed-XIAO-BLE-nRF52840-p-5201.html)
|
||||
* [Seeed XIAO ESP32C3](https://www.seeedstudio.com/Seeed-XIAO-ESP32C3-p-5431.html)
|
||||
* [Seeed XIAO RP2040](https://www.seeedstudio.com/XIAO-RP2040-v1-0-p-5026.html)
|
||||
* [Seeed LoRa-E5 Development Kit](https://www.seeedstudio.com/LoRa-E5-Dev-Kit-p-4868.html)
|
||||
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
|
||||
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
|
||||
* [SiFIve HiFive1 Rev B](https://www.sifive.com/boards/hifive1-rev-b)
|
||||
* [Sparkfun Thing Plus RP2040](https://www.sparkfun.com/products/17745)
|
||||
* [ST Micro "Nucleo" F103RB](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html)
|
||||
* [ST Micro "Nucleo" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
|
||||
* [ST Micro "Nucleo" L031K6](https://www.st.com/ja/evaluation-tools/nucleo-l031k6.html)
|
||||
* [ST Micro "Nucleo" L432KC](https://www.st.com/ja/evaluation-tools/nucleo-l432kc.html)
|
||||
* [ST Micro "Nucleo" L552ZE](https://www.st.com/en/evaluation-tools/nucleo-l552ze-q.html)
|
||||
* [ST Micro "Nucleo" WL55JC](https://www.st.com/en/evaluation-tools/nucleo-wl55jc.html)
|
||||
* [ST Micro STM32F103XX "Bluepill"](https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill)
|
||||
* [ST Micro STM32F407 "Discovery"](https://www.st.com/en/evaluation-tools/stm32f4discovery.html)
|
||||
* [ST Micro STM32F469 "Discovery"](https://www.st.com/content/st_com/en/products/evaluation-tools/product-evaluation-tools/mcu-mpu-eval-tools/stm32-mcu-mpu-eval-tools/stm32-discovery-kits/32f469idiscovery.html)
|
||||
* [The Things Industries Generic Node Sensor Edition](https://www.genericnode.com/docs/sensor-edition/)
|
||||
* [Waveshare RP2040-Zero](https://www.waveshare.com/wiki/RP2040-Zero)
|
||||
* [X9 Pro smartwatch](https://github.com/curtpw/nRF5x-device-reverse-engineering/tree/master/X9-nrf52832-activity-tracker/)
|
||||
|
||||
### WebAssembly
|
||||
|
||||
TinyGo programs can be compiled for both WASM and WASI targets.
|
||||
|
||||
For more information, see https://tinygo.org/docs/guides/webassembly/
|
||||
|
||||
### Operating Systems
|
||||
|
||||
You can also compile programs for Linux, macOS, and Windows targets.
|
||||
|
||||
For more information:
|
||||
|
||||
- Linux https://tinygo.org/docs/guides/linux/
|
||||
|
||||
- macOS https://tinygo.org/docs/guides/macos/
|
||||
|
||||
- Windows https://tinygo.org/docs/guides/windows/
|
||||
For more information, see [this list of boards](https://tinygo.org/microcontrollers/). Pull requests for additional support are welcome!
|
||||
|
||||
## Currently supported features:
|
||||
|
||||
|
||||
+1
-19
@@ -12,7 +12,6 @@ import (
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
wasm "github.com/aykevl/go-wasm"
|
||||
"github.com/blakesmith/ar"
|
||||
)
|
||||
|
||||
@@ -75,25 +74,8 @@ func makeArchive(arfile *os.File, objs []string) error {
|
||||
fileIndex int
|
||||
}{symbol.Name, i})
|
||||
}
|
||||
} else if dbg, err := wasm.Parse(objfile); err == nil {
|
||||
for _, s := range dbg.Sections {
|
||||
switch section := s.(type) {
|
||||
case *wasm.SectionImport:
|
||||
for _, ln := range section.Entries {
|
||||
|
||||
if ln.Kind != wasm.ExtKindFunction {
|
||||
// Not a function
|
||||
continue
|
||||
}
|
||||
symbolTable = append(symbolTable, struct {
|
||||
name string
|
||||
fileIndex int
|
||||
}{ln.Field, i})
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return fmt.Errorf("failed to open file %s as WASM, ELF or PE/COFF: %w", objpath, err)
|
||||
return fmt.Errorf("failed to open file %s as ELF or PE/COFF: %w", objpath, err)
|
||||
}
|
||||
|
||||
// Close file, to avoid issues with too many open files (especially on
|
||||
|
||||
+21
-13
@@ -175,7 +175,7 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
AutomaticStackSize: config.AutomaticStackSize(),
|
||||
DefaultStackSize: config.StackSize(),
|
||||
NeedsStackObjects: config.NeedsStackObjects(),
|
||||
Debug: !config.Options.SkipDWARF, // emit DWARF except when -internal-nodwarf is passed
|
||||
Debug: true,
|
||||
}
|
||||
|
||||
// Load the target machine, which is the LLVM object that contains all
|
||||
@@ -217,27 +217,19 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
var packageJobs []*compileJob
|
||||
packageActionIDJobs := make(map[string]*compileJob)
|
||||
|
||||
if config.Options.GlobalValues == nil {
|
||||
config.Options.GlobalValues = make(map[string]map[string]string)
|
||||
}
|
||||
if config.Options.GlobalValues["runtime"]["buildVersion"] == "" {
|
||||
version := goenv.Version
|
||||
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
|
||||
version += "-" + goenv.GitSha1
|
||||
}
|
||||
if config.Options.GlobalValues == nil {
|
||||
config.Options.GlobalValues = make(map[string]map[string]string)
|
||||
}
|
||||
if config.Options.GlobalValues["runtime"] == nil {
|
||||
config.Options.GlobalValues["runtime"] = make(map[string]string)
|
||||
}
|
||||
config.Options.GlobalValues["runtime"]["buildVersion"] = version
|
||||
}
|
||||
if config.TestConfig.CompileTestBinary {
|
||||
// The testing.testBinary is set to "1" when in a test.
|
||||
// This is needed for testing.Testing() to work correctly.
|
||||
if config.Options.GlobalValues["testing"] == nil {
|
||||
config.Options.GlobalValues["testing"] = make(map[string]string)
|
||||
}
|
||||
config.Options.GlobalValues["testing"]["testBinary"] = "1"
|
||||
}
|
||||
|
||||
var embedFileObjects []*compileJob
|
||||
for _, pkg := range lprogram.Sorted() {
|
||||
@@ -917,8 +909,13 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
|
||||
}
|
||||
case "nrf-dfu":
|
||||
// special format for nrfutil for Nordic chips
|
||||
tmphexpath := filepath.Join(tmpdir, "main.hex")
|
||||
err := objcopy(result.Executable, tmphexpath, "hex")
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result.Binary = filepath.Join(tmpdir, "main"+outext)
|
||||
err = makeDFUFirmwareImage(config.Options, result.Executable, result.Binary)
|
||||
err = makeDFUFirmwareImage(config.Options, tmphexpath, result.Binary)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
@@ -1062,6 +1059,17 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Browsers cannot handle external functions that have type i64 because it
|
||||
// cannot be represented exactly in JavaScript (JS only has doubles). To
|
||||
// keep functions interoperable, pass int64 types as pointers to
|
||||
// stack-allocated values.
|
||||
if config.WasmAbi() == "js" {
|
||||
err := transform.ExternalInt64AsPtr(mod, config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Optimization levels here are roughly the same as Clang, but probably not
|
||||
// exactly.
|
||||
optLevel, sizeLevel, inlinerThreshold := config.OptLevels()
|
||||
|
||||
@@ -60,7 +60,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" {
|
||||
|
||||
+11
-7
@@ -1,6 +1,7 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
@@ -23,14 +24,17 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
||||
spec.OpenOCDCommands = options.OpenOCDCommands
|
||||
}
|
||||
|
||||
major, minor, err := goenv.GetGorootVersion()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
goroot := goenv.Get("GOROOT")
|
||||
if goroot == "" {
|
||||
return nil, errors.New("cannot locate $GOROOT, please set it manually")
|
||||
}
|
||||
if major != 1 || minor < 18 || minor > 21 {
|
||||
// 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.18 through 1.21, got go%d.%d", major, minor)
|
||||
|
||||
major, minor, err := goenv.GetGorootVersion(goroot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
|
||||
}
|
||||
if major != 1 || minor < 18 || minor > 20 {
|
||||
return nil, fmt.Errorf("requires go version 1.18 through 1.20, got go%d.%d", major, minor)
|
||||
}
|
||||
|
||||
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ type espImageSegment struct {
|
||||
data []byte
|
||||
}
|
||||
|
||||
// makeESPFirmareImage converts an input ELF file to an image file for an ESP32 or
|
||||
// makeESPFirmare converts an input ELF file to an image file for an ESP32 or
|
||||
// ESP8266 chip. This is a special purpose image format just for the ESP chip
|
||||
// family, and is parsed by the on-chip mask ROM bootloader.
|
||||
//
|
||||
|
||||
+1
-1
@@ -134,7 +134,7 @@ func runJobs(job *compileJob, sema chan struct{}) error {
|
||||
numRunningJobs--
|
||||
<-sema
|
||||
if jobRunnerDebug {
|
||||
fmt.Println("## finished:", completed.description, "(time "+completed.duration.String()+")")
|
||||
fmt.Println("## finished:", job.description, "(time "+job.duration.String()+")")
|
||||
}
|
||||
if completed.err != nil {
|
||||
// Wait for any current jobs to finish.
|
||||
|
||||
+13
-103
@@ -1,117 +1,27 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
|
||||
"github.com/sigurn/crc16"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
)
|
||||
|
||||
// Structure of the manifest.json file.
|
||||
type jsonManifest struct {
|
||||
Manifest struct {
|
||||
Application struct {
|
||||
BinaryFile string `json:"bin_file"`
|
||||
DataFile string `json:"dat_file"`
|
||||
InitPacketData nrfInitPacket `json:"init_packet_data"`
|
||||
} `json:"application"`
|
||||
DFUVersion float64 `json:"dfu_version"` // yes, this is a JSON number, not a string
|
||||
} `json:"manifest"`
|
||||
}
|
||||
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fug_nrfutil%2FUG%2Fnrfutil%2Fnrfutil_intro.html
|
||||
|
||||
// Structure of the init packet.
|
||||
// Source:
|
||||
// https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/master/lib/sdk11/components/libraries/bootloader_dfu/dfu_init.h#L47-L57
|
||||
type nrfInitPacket struct {
|
||||
ApplicationVersion uint32 `json:"application_version"`
|
||||
DeviceRevision uint16 `json:"device_revision"`
|
||||
DeviceType uint16 `json:"device_type"`
|
||||
FirmwareCRC16 uint16 `json:"firmware_crc16"`
|
||||
SoftDeviceRequired []uint16 `json:"softdevice_req"` // this is actually a variable length array
|
||||
}
|
||||
|
||||
// Create the init packet (the contents of application.dat).
|
||||
func (p nrfInitPacket) createInitPacket() []byte {
|
||||
buf := &bytes.Buffer{}
|
||||
binary.Write(buf, binary.LittleEndian, p.DeviceType) // uint16_t device_type;
|
||||
binary.Write(buf, binary.LittleEndian, p.DeviceRevision) // uint16_t device_rev;
|
||||
binary.Write(buf, binary.LittleEndian, p.ApplicationVersion) // uint32_t app_version;
|
||||
binary.Write(buf, binary.LittleEndian, uint16(len(p.SoftDeviceRequired))) // uint16_t softdevice_len;
|
||||
binary.Write(buf, binary.LittleEndian, p.SoftDeviceRequired) // uint16_t softdevice[1];
|
||||
binary.Write(buf, binary.LittleEndian, p.FirmwareCRC16)
|
||||
return buf.Bytes()
|
||||
}
|
||||
|
||||
// Make a Nordic DFU firmware image from an ELF file.
|
||||
func makeDFUFirmwareImage(options *compileopts.Options, infile, outfile string) error {
|
||||
// Read ELF file as input and convert it to a binary image file.
|
||||
_, data, err := extractROM(infile)
|
||||
if err != nil {
|
||||
return err
|
||||
cmdLine := []string{"nrfutil", "pkg", "generate", "--hw-version", "52", "--sd-req", "0x0", "--debug-mode", "--application", infile, outfile}
|
||||
|
||||
if options.PrintCommands != nil {
|
||||
options.PrintCommands(cmdLine[0], cmdLine[1:]...)
|
||||
}
|
||||
|
||||
// Create the zip file in memory.
|
||||
// It won't be very large anyway.
|
||||
buf := &bytes.Buffer{}
|
||||
w := zip.NewWriter(buf)
|
||||
|
||||
// Write the application binary to the zip file.
|
||||
binw, err := w.Create("application.bin")
|
||||
cmd := exec.Command(cmdLine[0], cmdLine[1:]...)
|
||||
cmd.Stdout = io.Discard
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("could not run nrfutil pkg generate: %w", err)
|
||||
}
|
||||
_, err = binw.Write(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the init packet.
|
||||
initPacket := nrfInitPacket{
|
||||
ApplicationVersion: 0xffff_ffff, // appears to be unused by the Adafruit bootloader
|
||||
DeviceRevision: 0xffff, // DFU_DEVICE_REVISION_EMPTY
|
||||
DeviceType: 0x0052, // ADAFRUIT_DEVICE_TYPE
|
||||
FirmwareCRC16: crc16.Checksum(data, crc16.MakeTable(crc16.CRC16_CCITT_FALSE)),
|
||||
SoftDeviceRequired: []uint16{0xfffe}, // DFU_SOFTDEVICE_ANY
|
||||
}
|
||||
|
||||
// Write the init packet to the zip file.
|
||||
datw, err := w.Create("application.dat")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = datw.Write(initPacket.createInitPacket())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the JSON manifest.
|
||||
manifest := &jsonManifest{}
|
||||
manifest.Manifest.Application.BinaryFile = "application.bin"
|
||||
manifest.Manifest.Application.DataFile = "application.dat"
|
||||
manifest.Manifest.Application.InitPacketData = initPacket
|
||||
manifest.Manifest.DFUVersion = 0.5
|
||||
|
||||
// Write the JSON manifest to the file.
|
||||
jsonw, err := w.Create("manifest.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
enc := json.NewEncoder(jsonw)
|
||||
enc.SetIndent("", " ")
|
||||
err = enc.Encode(manifest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Finish the zip file.
|
||||
err = w.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return os.WriteFile(outfile, buf.Bytes(), 0o666)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -41,9 +41,9 @@ func TestBinarySize(t *testing.T) {
|
||||
// This is a small number of very diverse targets that we want to test.
|
||||
tests := []sizeTest{
|
||||
// microcontrollers
|
||||
{"hifive1b", "examples/echo", 4612, 280, 0, 2252},
|
||||
{"microbit", "examples/serial", 2724, 388, 8, 2256},
|
||||
{"wioterminal", "examples/pininterrupt", 6039, 1485, 116, 6816},
|
||||
{"hifive1b", "examples/echo", 4556, 272, 0, 2252},
|
||||
{"microbit", "examples/serial", 2680, 380, 8, 2256},
|
||||
{"wioterminal", "examples/pininterrupt", 6109, 1471, 116, 6816},
|
||||
|
||||
// TODO: also check wasm. Right now this is difficult, because
|
||||
// wasm binaries are run through wasm-opt and therefore the
|
||||
|
||||
@@ -142,7 +142,6 @@ var validLinkerFlags = []*regexp.Regexp{
|
||||
re(`-L([^@\-].*)`),
|
||||
re(`-O`),
|
||||
re(`-O([^@\-].*)`),
|
||||
re(`--export=([^@\-].*)`),
|
||||
re(`-f(no-)?(pic|PIC|pie|PIE)`),
|
||||
re(`-f(no-)?openmp(-simd)?`),
|
||||
re(`-fsanitize=([^@\-].*)`),
|
||||
|
||||
@@ -108,7 +108,6 @@ var goodLinkerFlags = [][]string{
|
||||
{"-Fbar"},
|
||||
{"-lbar"},
|
||||
{"-Lbar"},
|
||||
{"--export=my_symbol"},
|
||||
{"-fpic"},
|
||||
{"-fno-pic"},
|
||||
{"-fPIC"},
|
||||
|
||||
+31
-3
@@ -75,7 +75,8 @@ func (c *Config) GOARM() string {
|
||||
|
||||
// BuildTags returns the complete list of build tags used during this build.
|
||||
func (c *Config) BuildTags() []string {
|
||||
tags := append(c.Target.BuildTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
|
||||
targetTags := filterTags(c.Target.BuildTags, c.Options.Tags)
|
||||
tags := append(targetTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
|
||||
for i := 1; i <= c.GoMinorVersion; i++ {
|
||||
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
||||
}
|
||||
@@ -492,6 +493,11 @@ func (c *Config) RelocationModel() string {
|
||||
return "static"
|
||||
}
|
||||
|
||||
// WasmAbi returns the WASM ABI which is specified in the target JSON file.
|
||||
func (c *Config) WasmAbi() string {
|
||||
return c.Target.WasmAbi
|
||||
}
|
||||
|
||||
// EmulatorName is a shorthand to get the command for this emulator, something
|
||||
// like qemu-system-arm or simavr.
|
||||
func (c *Config) EmulatorName() string {
|
||||
@@ -539,10 +545,32 @@ type TestConfig struct {
|
||||
Verbose bool
|
||||
Short bool
|
||||
RunRegexp string
|
||||
SkipRegexp string
|
||||
Count *int
|
||||
BenchRegexp string
|
||||
BenchTime string
|
||||
BenchMem bool
|
||||
Shuffle string
|
||||
}
|
||||
|
||||
// filterTags removes predefined build tags for a target if a conflicting option
|
||||
// is provided by the user.
|
||||
func filterTags(targetTags []string, userTags []string) []string {
|
||||
var filtered []string
|
||||
for _, t := range targetTags {
|
||||
switch {
|
||||
case strings.HasPrefix(t, "runtime_memhash_"):
|
||||
overridden := false
|
||||
for _, ut := range userTags {
|
||||
if strings.HasPrefix(ut, "runtime_memhash_") {
|
||||
overridden = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !overridden {
|
||||
filtered = append(filtered, t)
|
||||
}
|
||||
default:
|
||||
filtered = append(filtered, t)
|
||||
}
|
||||
}
|
||||
return filtered
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
package compileopts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestBuildTags(t *testing.T) {
|
||||
tests := []struct {
|
||||
targetTags []string
|
||||
userTags []string
|
||||
result []string
|
||||
}{
|
||||
{
|
||||
targetTags: []string{},
|
||||
userTags: []string{},
|
||||
result: []string{
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{"bear"},
|
||||
userTags: []string{},
|
||||
result: []string{
|
||||
"bear",
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{},
|
||||
userTags: []string{"cat"},
|
||||
result: []string{
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
"cat",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{"bear"},
|
||||
userTags: []string{"cat"},
|
||||
result: []string{
|
||||
"bear",
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
"cat",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{"bear", "runtime_memhash_leveldb"},
|
||||
userTags: []string{"cat"},
|
||||
result: []string{
|
||||
"bear",
|
||||
"runtime_memhash_leveldb",
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
"cat",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{"bear", "runtime_memhash_leveldb"},
|
||||
userTags: []string{"cat", "runtime_memhash_leveldb"},
|
||||
result: []string{
|
||||
"bear",
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
"cat",
|
||||
"runtime_memhash_leveldb",
|
||||
},
|
||||
},
|
||||
{
|
||||
targetTags: []string{"bear", "runtime_memhash_leveldb"},
|
||||
userTags: []string{"cat", "runtime_memhash_sip"},
|
||||
result: []string{
|
||||
"bear",
|
||||
"tinygo",
|
||||
"math_big_pure_go",
|
||||
"gc.conservative",
|
||||
"scheduler.none",
|
||||
"serial.none",
|
||||
"cat",
|
||||
"runtime_memhash_sip",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tt := tc
|
||||
t.Run(fmt.Sprintf("%s+%s", strings.Join(tt.targetTags, ","), strings.Join(tt.userTags, ",")), func(t *testing.T) {
|
||||
c := &Config{
|
||||
Target: &TargetSpec{
|
||||
BuildTags: tt.targetTags,
|
||||
},
|
||||
Options: &Options{
|
||||
Tags: tt.userTags,
|
||||
},
|
||||
}
|
||||
|
||||
res := c.BuildTags()
|
||||
|
||||
if len(res) != len(tt.result) {
|
||||
t.Errorf("expected %d tags, got %d", len(tt.result), len(res))
|
||||
}
|
||||
|
||||
for i, tag := range tt.result {
|
||||
if tag != res[i] {
|
||||
t.Errorf("tag %d: expected %s, got %s", i, tt.result[i], tag)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,6 @@ type Options struct {
|
||||
PrintIR bool
|
||||
DumpSSA bool
|
||||
VerifyIR bool
|
||||
SkipDWARF bool
|
||||
PrintCommands func(cmd string, args ...string) `json:"-"`
|
||||
Semaphore chan struct{} `json:"-"` // -p flag controls cap
|
||||
Debug bool
|
||||
|
||||
+41
-70
@@ -23,45 +23,46 @@ import (
|
||||
// https://doc.rust-lang.org/nightly/nightly-rustc/rustc_target/spec/struct.TargetOptions.html
|
||||
// https://github.com/shepmaster/rust-arduino-blink-led-no-core-with-cargo/blob/master/blink/arduino.json
|
||||
type TargetSpec struct {
|
||||
Inherits []string `json:"inherits,omitempty"`
|
||||
Triple string `json:"llvm-target,omitempty"`
|
||||
CPU string `json:"cpu,omitempty"`
|
||||
ABI string `json:"target-abi,omitempty"` // rougly equivalent to -mabi= flag
|
||||
Features string `json:"features,omitempty"`
|
||||
GOOS string `json:"goos,omitempty"`
|
||||
GOARCH string `json:"goarch,omitempty"`
|
||||
BuildTags []string `json:"build-tags,omitempty"`
|
||||
GC string `json:"gc,omitempty"`
|
||||
Scheduler string `json:"scheduler,omitempty"`
|
||||
Serial string `json:"serial,omitempty"` // which serial output to use (uart, usb, none)
|
||||
Linker string `json:"linker,omitempty"`
|
||||
RTLib string `json:"rtlib,omitempty"` // compiler runtime library (libgcc, compiler-rt)
|
||||
Libc string `json:"libc,omitempty"`
|
||||
AutoStackSize *bool `json:"automatic-stack-size,omitempty"` // Determine stack size automatically at compile time.
|
||||
DefaultStackSize uint64 `json:"default-stack-size,omitempty"` // Default stack size if the size couldn't be determined at compile time.
|
||||
CFlags []string `json:"cflags,omitempty"`
|
||||
LDFlags []string `json:"ldflags,omitempty"`
|
||||
LinkerScript string `json:"linkerscript,omitempty"`
|
||||
ExtraFiles []string `json:"extra-files,omitempty"`
|
||||
RP2040BootPatch *bool `json:"rp2040-boot-patch,omitempty"` // Patch RP2040 2nd stage bootloader checksum
|
||||
Emulator string `json:"emulator,omitempty"`
|
||||
FlashCommand string `json:"flash-command,omitempty"`
|
||||
GDB []string `json:"gdb,omitempty"`
|
||||
PortReset string `json:"flash-1200-bps-reset,omitempty"`
|
||||
SerialPort []string `json:"serial-port,omitempty"` // serial port IDs in the form "vid:pid"
|
||||
FlashMethod string `json:"flash-method,omitempty"`
|
||||
FlashVolume []string `json:"msd-volume-name,omitempty"`
|
||||
FlashFilename string `json:"msd-firmware-name,omitempty"`
|
||||
UF2FamilyID string `json:"uf2-family-id,omitempty"`
|
||||
BinaryFormat string `json:"binary-format,omitempty"`
|
||||
OpenOCDInterface string `json:"openocd-interface,omitempty"`
|
||||
OpenOCDTarget string `json:"openocd-target,omitempty"`
|
||||
OpenOCDTransport string `json:"openocd-transport,omitempty"`
|
||||
OpenOCDCommands []string `json:"openocd-commands,omitempty"`
|
||||
OpenOCDVerify *bool `json:"openocd-verify,omitempty"` // enable verify when flashing with openocd
|
||||
JLinkDevice string `json:"jlink-device,omitempty"`
|
||||
CodeModel string `json:"code-model,omitempty"`
|
||||
RelocationModel string `json:"relocation-model,omitempty"`
|
||||
Inherits []string `json:"inherits"`
|
||||
Triple string `json:"llvm-target"`
|
||||
CPU string `json:"cpu"`
|
||||
ABI string `json:"target-abi"` // rougly equivalent to -mabi= flag
|
||||
Features string `json:"features"`
|
||||
GOOS string `json:"goos"`
|
||||
GOARCH string `json:"goarch"`
|
||||
BuildTags []string `json:"build-tags"`
|
||||
GC string `json:"gc"`
|
||||
Scheduler string `json:"scheduler"`
|
||||
Serial string `json:"serial"` // which serial output to use (uart, usb, none)
|
||||
Linker string `json:"linker"`
|
||||
RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt)
|
||||
Libc string `json:"libc"`
|
||||
AutoStackSize *bool `json:"automatic-stack-size"` // Determine stack size automatically at compile time.
|
||||
DefaultStackSize uint64 `json:"default-stack-size"` // Default stack size if the size couldn't be determined at compile time.
|
||||
CFlags []string `json:"cflags"`
|
||||
LDFlags []string `json:"ldflags"`
|
||||
LinkerScript string `json:"linkerscript"`
|
||||
ExtraFiles []string `json:"extra-files"`
|
||||
RP2040BootPatch *bool `json:"rp2040-boot-patch"` // Patch RP2040 2nd stage bootloader checksum
|
||||
Emulator string `json:"emulator"`
|
||||
FlashCommand string `json:"flash-command"`
|
||||
GDB []string `json:"gdb"`
|
||||
PortReset string `json:"flash-1200-bps-reset"`
|
||||
SerialPort []string `json:"serial-port"` // serial port IDs in the form "vid:pid"
|
||||
FlashMethod string `json:"flash-method"`
|
||||
FlashVolume string `json:"msd-volume-name"`
|
||||
FlashFilename string `json:"msd-firmware-name"`
|
||||
UF2FamilyID string `json:"uf2-family-id"`
|
||||
BinaryFormat string `json:"binary-format"`
|
||||
OpenOCDInterface string `json:"openocd-interface"`
|
||||
OpenOCDTarget string `json:"openocd-target"`
|
||||
OpenOCDTransport string `json:"openocd-transport"`
|
||||
OpenOCDCommands []string `json:"openocd-commands"`
|
||||
OpenOCDVerify *bool `json:"openocd-verify"` // enable verify when flashing with openocd
|
||||
JLinkDevice string `json:"jlink-device"`
|
||||
CodeModel string `json:"code-model"`
|
||||
RelocationModel string `json:"relocation-model"`
|
||||
WasmAbi string `json:"wasm-abi"`
|
||||
}
|
||||
|
||||
// overrideProperties overrides all properties that are set in child into itself using reflection.
|
||||
@@ -191,15 +192,12 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid GOARM=%s, must be 5, 6, or 7", options.GOARM)
|
||||
}
|
||||
case "wasm":
|
||||
llvmarch = "wasm32"
|
||||
default:
|
||||
llvmarch = options.GOARCH
|
||||
}
|
||||
llvmvendor := "unknown"
|
||||
llvmos := options.GOOS
|
||||
switch llvmos {
|
||||
case "darwin":
|
||||
if llvmos == "darwin" {
|
||||
// Use macosx* instead of darwin, otherwise darwin/arm64 will refer
|
||||
// to iOS!
|
||||
llvmos = "macosx10.12.0"
|
||||
@@ -210,8 +208,6 @@ func LoadTarget(options *Options) (*TargetSpec, error) {
|
||||
llvmos = "macosx11.0.0"
|
||||
}
|
||||
llvmvendor = "apple"
|
||||
case "wasip1":
|
||||
llvmos = "wasi"
|
||||
}
|
||||
// Target triples (which actually have four components, but are called
|
||||
// triples for historical reasons) have the form:
|
||||
@@ -282,15 +278,6 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
case "arm64":
|
||||
spec.CPU = "generic"
|
||||
spec.Features = "+neon"
|
||||
case "wasm":
|
||||
spec.CPU = "generic"
|
||||
spec.Features = "+bulk-memory,+nontrapping-fptoint,+sign-ext"
|
||||
spec.BuildTags = append(spec.BuildTags, "tinygo.wasm")
|
||||
spec.CFlags = append(spec.CFlags,
|
||||
"-mbulk-memory",
|
||||
"-mnontrapping-fptoint",
|
||||
"-msign-ext",
|
||||
)
|
||||
}
|
||||
if goos == "darwin" {
|
||||
spec.Linker = "ld.lld"
|
||||
@@ -334,22 +321,6 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
"--no-insert-timestamp",
|
||||
"--no-dynamicbase",
|
||||
)
|
||||
} else if goos == "wasip1" {
|
||||
spec.GC = "" // use default GC
|
||||
spec.Scheduler = "asyncify"
|
||||
spec.Linker = "wasm-ld"
|
||||
spec.RTLib = "compiler-rt"
|
||||
spec.Libc = "wasi-libc"
|
||||
spec.DefaultStackSize = 1024 * 16 // 16kB
|
||||
spec.LDFlags = append(spec.LDFlags,
|
||||
"--stack-first",
|
||||
"--no-demangle",
|
||||
)
|
||||
spec.Emulator = "wasmtime --mapdir=/tmp::{tmpDir} {}"
|
||||
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||
"src/runtime/asm_tinygowasm.S",
|
||||
"src/internal/task/task_asyncify_wasm.S",
|
||||
)
|
||||
} else {
|
||||
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
|
||||
}
|
||||
|
||||
+2
-6
@@ -36,11 +36,7 @@ const (
|
||||
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
|
||||
// createRuntimeInvoke instead.
|
||||
func (b *builder) createRuntimeCallCommon(fnName string, args []llvm.Value, name string, isInvoke bool) llvm.Value {
|
||||
member := b.program.ImportedPackage("runtime").Members[fnName]
|
||||
if member == nil {
|
||||
panic("unknown runtime call: " + fnName)
|
||||
}
|
||||
fn := member.(*ssa.Function)
|
||||
fn := b.program.ImportedPackage("runtime").Members[fnName].(*ssa.Function)
|
||||
fnType, llvmFn := b.getFunction(fn)
|
||||
if llvmFn.IsNil() {
|
||||
panic("trying to call non-existent function: " + fn.RelString(nil))
|
||||
@@ -233,7 +229,7 @@ func extractSubfield(t types.Type, field int) types.Type {
|
||||
}
|
||||
}
|
||||
|
||||
// flattenAggregateTypeOffsets returns the offsets from the start of an object of
|
||||
// flattenAggregateTypeOffset returns the offsets from the start of an object of
|
||||
// type t if this object were flattened like in flattenAggregate. Used together
|
||||
// with flattenAggregate to know the start indices of each value in the
|
||||
// non-flattened object.
|
||||
|
||||
+8
-85
@@ -82,7 +82,6 @@ type compilerContext struct {
|
||||
uintptrType llvm.Type
|
||||
program *ssa.Program
|
||||
diagnostics []error
|
||||
functionInfos map[*ssa.Function]functionInfo
|
||||
astComments map[string]*ast.CommentGroup
|
||||
embedGlobals map[string][]*loader.EmbedFile
|
||||
pkg *types.Package
|
||||
@@ -94,14 +93,13 @@ type compilerContext struct {
|
||||
// importantly with a newly created LLVM context and module.
|
||||
func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *Config, dumpSSA bool) *compilerContext {
|
||||
c := &compilerContext{
|
||||
Config: config,
|
||||
DumpSSA: dumpSSA,
|
||||
difiles: make(map[string]llvm.Metadata),
|
||||
ditypes: make(map[types.Type]llvm.Metadata),
|
||||
machine: machine,
|
||||
targetData: machine.CreateTargetData(),
|
||||
functionInfos: map[*ssa.Function]functionInfo{},
|
||||
astComments: map[string]*ast.CommentGroup{},
|
||||
Config: config,
|
||||
DumpSSA: dumpSSA,
|
||||
difiles: make(map[string]llvm.Metadata),
|
||||
ditypes: make(map[types.Type]llvm.Metadata),
|
||||
machine: machine,
|
||||
targetData: machine.CreateTargetData(),
|
||||
astComments: map[string]*ast.CommentGroup{},
|
||||
}
|
||||
|
||||
c.ctx = llvm.NewContext()
|
||||
@@ -169,8 +167,6 @@ type builder struct {
|
||||
deferExprFuncs map[ssa.Value]int
|
||||
selectRecvBuf map[*ssa.Select]llvm.Value
|
||||
deferBuiltinFuncs map[ssa.Value]deferBuiltin
|
||||
runDefersBlock []llvm.BasicBlock
|
||||
afterDefersBlock []llvm.BasicBlock
|
||||
}
|
||||
|
||||
func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *builder {
|
||||
@@ -1353,15 +1349,6 @@ func (b *builder) createFunction() {
|
||||
}
|
||||
}
|
||||
|
||||
// The rundefers instruction needs to be created after all defer
|
||||
// instructions have been created. Otherwise it won't handle all defer
|
||||
// cases.
|
||||
for i, bb := range b.runDefersBlock {
|
||||
b.SetInsertPointAtEnd(bb)
|
||||
b.createRunDefers()
|
||||
b.CreateBr(b.afterDefersBlock[i])
|
||||
}
|
||||
|
||||
if b.hasDeferFrame() {
|
||||
// Create the landing pad block, where execution continues after a
|
||||
// panic.
|
||||
@@ -1516,14 +1503,7 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
|
||||
b.CreateRet(retVal)
|
||||
}
|
||||
case *ssa.RunDefers:
|
||||
// Note where we're going to put the rundefers block
|
||||
run := b.insertBasicBlock("rundefers.block")
|
||||
b.CreateBr(run)
|
||||
b.runDefersBlock = append(b.runDefersBlock, run)
|
||||
|
||||
after := b.insertBasicBlock("rundefers.after")
|
||||
b.SetInsertPointAtEnd(after)
|
||||
b.afterDefersBlock = append(b.afterDefersBlock, after)
|
||||
b.createRunDefers()
|
||||
case *ssa.Send:
|
||||
b.createChanSend(instr)
|
||||
case *ssa.Store:
|
||||
@@ -1600,45 +1580,6 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
||||
cplx = b.CreateInsertValue(cplx, r, 0, "")
|
||||
cplx = b.CreateInsertValue(cplx, i, 1, "")
|
||||
return cplx, nil
|
||||
case "clear":
|
||||
value := argValues[0]
|
||||
switch typ := argTypes[0].Underlying().(type) {
|
||||
case *types.Slice:
|
||||
elementType := b.getLLVMType(typ.Elem())
|
||||
elementSize := b.targetData.TypeAllocSize(elementType)
|
||||
elementAlign := b.targetData.ABITypeAlignment(elementType)
|
||||
|
||||
// The pointer to the data to be cleared.
|
||||
llvmBuf := b.CreateExtractValue(value, 0, "buf")
|
||||
if llvmBuf.Type() != b.i8ptrType { // compatibility with LLVM 14
|
||||
llvmBuf = b.CreateBitCast(llvmBuf, b.i8ptrType, "")
|
||||
}
|
||||
|
||||
// The length (in bytes) to be cleared.
|
||||
llvmLen := b.CreateExtractValue(value, 1, "len")
|
||||
llvmLen = b.CreateMul(llvmLen, llvm.ConstInt(llvmLen.Type(), elementSize, false), "")
|
||||
|
||||
// Do the clear operation using the LLVM memset builtin.
|
||||
// This is also correct for nil slices: in those cases, len will be
|
||||
// 0 which means the memset call is a no-op (according to the LLVM
|
||||
// LangRef).
|
||||
memset := b.getMemsetFunc()
|
||||
call := b.createCall(memset.GlobalValueType(), memset, []llvm.Value{
|
||||
llvmBuf, // dest
|
||||
llvm.ConstInt(b.ctx.Int8Type(), 0, false), // val
|
||||
llvmLen, // len
|
||||
llvm.ConstInt(b.ctx.Int1Type(), 0, false), // isVolatile
|
||||
}, "")
|
||||
call.AddCallSiteAttribute(1, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elementAlign)))
|
||||
|
||||
return llvm.Value{}, nil
|
||||
case *types.Map:
|
||||
m := argValues[0]
|
||||
b.createMapClear(m)
|
||||
return llvm.Value{}, nil
|
||||
default:
|
||||
return llvm.Value{}, b.makeError(pos, "unsupported type in clear builtin: "+typ.String())
|
||||
}
|
||||
case "copy":
|
||||
dst := argValues[0]
|
||||
src := argValues[1]
|
||||
@@ -1676,24 +1617,6 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
|
||||
llvmLen = b.CreateZExt(llvmLen, b.intType, "len.int")
|
||||
}
|
||||
return llvmLen, nil
|
||||
case "min", "max":
|
||||
// min and max builtins, added in Go 1.21.
|
||||
// We can simply reuse the existing binop comparison code, which has all
|
||||
// the edge cases figured out already.
|
||||
tok := token.LSS
|
||||
if callName == "max" {
|
||||
tok = token.GTR
|
||||
}
|
||||
result := argValues[0]
|
||||
typ := argTypes[0]
|
||||
for _, arg := range argValues[1:] {
|
||||
cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
result = b.CreateSelect(cmp, result, arg, "")
|
||||
}
|
||||
return result, nil
|
||||
case "print", "println":
|
||||
for i, value := range argValues {
|
||||
if i >= 1 && callName == "println" {
|
||||
|
||||
+44
-89
@@ -29,7 +29,7 @@ func TestCompiler(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Determine Go minor version (e.g. 16 in go1.16.3).
|
||||
_, goMinor, err := goenv.GetGorootVersion()
|
||||
_, goMinor, err := goenv.GetGorootVersion(goenv.Get("GOROOT"))
|
||||
if err != nil {
|
||||
t.Fatal("could not read Go version:", err)
|
||||
}
|
||||
@@ -54,9 +54,6 @@ func TestCompiler(t *testing.T) {
|
||||
if goMinor >= 20 {
|
||||
tests = append(tests, testCase{"go1.20.go", "", ""})
|
||||
}
|
||||
if goMinor >= 21 {
|
||||
tests = append(tests, testCase{"go1.21.go", "", ""})
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
name := tc.file
|
||||
@@ -73,11 +70,52 @@ func TestCompiler(t *testing.T) {
|
||||
options := &compileopts.Options{
|
||||
Target: targetString,
|
||||
}
|
||||
target, err := compileopts.LoadTarget(options)
|
||||
if err != nil {
|
||||
t.Fatal("failed to load target:", err)
|
||||
}
|
||||
if tc.scheduler != "" {
|
||||
options.Scheduler = tc.scheduler
|
||||
}
|
||||
config := &compileopts.Config{
|
||||
Options: options,
|
||||
Target: target,
|
||||
}
|
||||
compilerConfig := &Config{
|
||||
Triple: config.Triple(),
|
||||
Features: config.Features(),
|
||||
ABI: config.ABI(),
|
||||
GOOS: config.GOOS(),
|
||||
GOARCH: config.GOARCH(),
|
||||
CodeModel: config.CodeModel(),
|
||||
RelocationModel: config.RelocationModel(),
|
||||
Scheduler: config.Scheduler(),
|
||||
AutomaticStackSize: config.AutomaticStackSize(),
|
||||
DefaultStackSize: config.StackSize(),
|
||||
NeedsStackObjects: config.NeedsStackObjects(),
|
||||
}
|
||||
machine, err := NewTargetMachine(compilerConfig)
|
||||
if err != nil {
|
||||
t.Fatal("failed to create target machine:", err)
|
||||
}
|
||||
defer machine.Dispose()
|
||||
|
||||
mod, errs := testCompilePackage(t, options, tc.file)
|
||||
// Load entire program AST into memory.
|
||||
lprogram, err := loader.Load(config, "./testdata/"+tc.file, config.ClangHeaders, types.Config{
|
||||
Sizes: Sizes(machine),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("failed to create target machine:", err)
|
||||
}
|
||||
err = lprogram.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse test case %s: %s", tc.file, err)
|
||||
}
|
||||
|
||||
// Compile AST to IR.
|
||||
program := lprogram.LoadSSA()
|
||||
pkg := lprogram.MainPkg()
|
||||
mod, errs := CompilePackage(tc.file, pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
|
||||
if errs != nil {
|
||||
for _, err := range errs {
|
||||
t.Error(err)
|
||||
@@ -85,7 +123,7 @@ func TestCompiler(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
err := llvm.VerifyModule(mod, llvm.PrintMessageAction)
|
||||
err = llvm.VerifyModule(mod, llvm.PrintMessageAction)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
@@ -178,86 +216,3 @@ func filterIrrelevantIRLines(lines []string) []string {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func TestCompilerErrors(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Read expected errors from the test file.
|
||||
var expectedErrors []string
|
||||
errorsFile, err := os.ReadFile("testdata/errors.go")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
errorsFileString := strings.ReplaceAll(string(errorsFile), "\r\n", "\n")
|
||||
for _, line := range strings.Split(errorsFileString, "\n") {
|
||||
if strings.HasPrefix(line, "// ERROR: ") {
|
||||
expectedErrors = append(expectedErrors, strings.TrimPrefix(line, "// ERROR: "))
|
||||
}
|
||||
}
|
||||
|
||||
// Compile the Go file with errors.
|
||||
options := &compileopts.Options{
|
||||
Target: "wasm",
|
||||
}
|
||||
_, errs := testCompilePackage(t, options, "errors.go")
|
||||
|
||||
// Check whether the actual errors match the expected errors.
|
||||
expectedErrorsIdx := 0
|
||||
for _, err := range errs {
|
||||
err := err.(types.Error)
|
||||
position := err.Fset.Position(err.Pos)
|
||||
position.Filename = "errors.go" // don't use a full path
|
||||
if expectedErrorsIdx >= len(expectedErrors) || expectedErrors[expectedErrorsIdx] != err.Msg {
|
||||
t.Errorf("unexpected compiler error: %s: %s", position.String(), err.Msg)
|
||||
continue
|
||||
}
|
||||
expectedErrorsIdx++
|
||||
}
|
||||
}
|
||||
|
||||
// Build a package given a number of compiler options and a file.
|
||||
func testCompilePackage(t *testing.T, options *compileopts.Options, file string) (llvm.Module, []error) {
|
||||
target, err := compileopts.LoadTarget(options)
|
||||
if err != nil {
|
||||
t.Fatal("failed to load target:", err)
|
||||
}
|
||||
config := &compileopts.Config{
|
||||
Options: options,
|
||||
Target: target,
|
||||
}
|
||||
compilerConfig := &Config{
|
||||
Triple: config.Triple(),
|
||||
Features: config.Features(),
|
||||
ABI: config.ABI(),
|
||||
GOOS: config.GOOS(),
|
||||
GOARCH: config.GOARCH(),
|
||||
CodeModel: config.CodeModel(),
|
||||
RelocationModel: config.RelocationModel(),
|
||||
Scheduler: config.Scheduler(),
|
||||
AutomaticStackSize: config.AutomaticStackSize(),
|
||||
DefaultStackSize: config.StackSize(),
|
||||
NeedsStackObjects: config.NeedsStackObjects(),
|
||||
}
|
||||
machine, err := NewTargetMachine(compilerConfig)
|
||||
if err != nil {
|
||||
t.Fatal("failed to create target machine:", err)
|
||||
}
|
||||
defer machine.Dispose()
|
||||
|
||||
// Load entire program AST into memory.
|
||||
lprogram, err := loader.Load(config, "./testdata/"+file, config.ClangHeaders, types.Config{
|
||||
Sizes: Sizes(machine),
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal("failed to create target machine:", err)
|
||||
}
|
||||
err = lprogram.Parse()
|
||||
if err != nil {
|
||||
t.Fatalf("could not parse test case %s: %s", file, err)
|
||||
}
|
||||
|
||||
// Compile AST to IR.
|
||||
program := lprogram.LoadSSA()
|
||||
pkg := lprogram.MainPkg()
|
||||
return CompilePackage(file, pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
|
||||
}
|
||||
|
||||
+15
-61
@@ -6,7 +6,6 @@ package compiler
|
||||
// interface-lowering.go for more details.
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"go/types"
|
||||
@@ -127,31 +126,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
if _, ok := typ.Underlying().(*types.Interface); ok {
|
||||
hasMethodSet = false
|
||||
}
|
||||
|
||||
var numMethods int
|
||||
if hasMethodSet {
|
||||
for i := 0; i < ms.Len(); i++ {
|
||||
if ms.At(i).Obj().Exported() {
|
||||
numMethods++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Short-circuit all the global pointer logic here for pointers to pointers.
|
||||
if typ, ok := typ.(*types.Pointer); ok {
|
||||
if _, ok := typ.Elem().(*types.Pointer); ok {
|
||||
// For a pointer to a pointer, we just increase the pointer by 1
|
||||
ptr := c.getTypeCode(typ.Elem())
|
||||
// if the type is already *****T or higher, we can't make it.
|
||||
if typstr := typ.String(); strings.HasPrefix(typstr, "*****") {
|
||||
c.addError(token.NoPos, fmt.Sprintf("too many levels of pointers for typecode: %s", typstr))
|
||||
}
|
||||
return llvm.ConstGEP(c.ctx.Int8Type(), ptr, []llvm.Value{
|
||||
llvm.ConstInt(llvm.Int32Type(), 1, false),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
typeCodeName, isLocal := getTypeCodeName(typ)
|
||||
globalName := "reflect/types.type:" + typeCodeName
|
||||
var global llvm.Value
|
||||
@@ -231,7 +205,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "size", types.Typ[types.Uint32]),
|
||||
types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
|
||||
)
|
||||
@@ -263,16 +236,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
c.interfaceTypes.Set(typ, global)
|
||||
}
|
||||
metabyte := getTypeKind(typ)
|
||||
|
||||
// Precompute these so we don't have to calculate them at runtime.
|
||||
if types.Comparable(typ) {
|
||||
metabyte |= 1 << 6
|
||||
}
|
||||
|
||||
if hashmapIsBinaryKey(typ) {
|
||||
metabyte |= 1 << 7
|
||||
}
|
||||
|
||||
switch typ := typ.(type) {
|
||||
case *types.Basic:
|
||||
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
|
||||
@@ -286,11 +249,11 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
}
|
||||
pkgPathPtr := c.pkgPathPtr(pkgpath)
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Underlying()), // underlying
|
||||
pkgPathPtr, // pkgpath pointer
|
||||
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Underlying()), // underlying
|
||||
pkgPathPtr, // pkgpath pointer
|
||||
c.ctx.ConstString(pkgname+"."+name+"\x00", false), // name
|
||||
}
|
||||
metabyte |= 1 << 5 // "named" flag
|
||||
case *types.Chan:
|
||||
@@ -317,7 +280,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
}
|
||||
case *types.Pointer:
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods
|
||||
c.getTypeCode(typ.Elem()),
|
||||
}
|
||||
case *types.Array:
|
||||
@@ -343,21 +306,16 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
}
|
||||
pkgPathPtr := c.pkgPathPtr(pkgpath)
|
||||
|
||||
llvmStructType := c.getLLVMType(typ)
|
||||
size := c.targetData.TypeStoreSize(llvmStructType)
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(numMethods), false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
pkgPathPtr,
|
||||
llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
|
||||
}
|
||||
structFieldType := c.getLLVMRuntimeType("structField")
|
||||
|
||||
var fields []llvm.Value
|
||||
for i := 0; i < typ.NumFields(); i++ {
|
||||
field := typ.Field(i)
|
||||
offset := c.targetData.ElementOffset(llvmStructType, i)
|
||||
var flags uint8
|
||||
if field.Anonymous() {
|
||||
flags |= structFieldFlagAnonymous
|
||||
@@ -371,11 +329,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
if field.Embedded() {
|
||||
flags |= structFieldFlagIsEmbedded
|
||||
}
|
||||
|
||||
var offsBytes [binary.MaxVarintLen32]byte
|
||||
offLen := binary.PutUvarint(offsBytes[:], offset)
|
||||
|
||||
data := string(flags) + string(offsBytes[:offLen]) + field.Name() + "\x00"
|
||||
data := string(flags) + field.Name() + "\x00"
|
||||
if typ.Tag(i) != "" {
|
||||
if len(typ.Tag(i)) > 0xff {
|
||||
c.addError(field.Pos(), fmt.Sprintf("struct tag is %d bytes which is too long, max is 255", len(typ.Tag(i))))
|
||||
@@ -416,9 +370,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||
}, typeFields...)
|
||||
}
|
||||
alignment := c.targetData.TypeAllocSize(c.i8ptrType)
|
||||
if alignment < 4 {
|
||||
alignment = 4
|
||||
}
|
||||
globalValue := c.ctx.ConstStruct(typeFields, false)
|
||||
global.SetInitializer(globalValue)
|
||||
if isLocal {
|
||||
@@ -696,8 +647,11 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
||||
commaOk = b.CreateCall(fn.GlobalValueType(), fn, []llvm.Value{actualTypeNum}, "")
|
||||
|
||||
} else {
|
||||
name, _ := getTypeCodeName(expr.AssertedType)
|
||||
globalName := "reflect/types.typeid:" + name
|
||||
assertedTypeGlobal := b.getTypeCode(expr.AssertedType)
|
||||
if !assertedTypeGlobal.IsAConstantExpr().IsNil() {
|
||||
assertedTypeGlobal = assertedTypeGlobal.Operand(0) // resolve the GEP operation
|
||||
}
|
||||
globalName := "reflect/types.typeid:" + strings.TrimPrefix(assertedTypeGlobal.Name(), "reflect/types.type:")
|
||||
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
|
||||
if assertedTypeCodeGlobal.IsNil() {
|
||||
// Create a new typecode global.
|
||||
@@ -770,7 +724,7 @@ func (c *compilerContext) getMethodsString(itf *types.Interface) string {
|
||||
return strings.Join(methods, "; ")
|
||||
}
|
||||
|
||||
// getInterfaceImplementsFunc returns a declared function that works as a type
|
||||
// getInterfaceImplementsfunc returns a declared function that works as a type
|
||||
// switch. The interface lowering pass will define this function.
|
||||
func (c *compilerContext) getInterfaceImplementsFunc(assertedType types.Type) llvm.Value {
|
||||
s, _ := getTypeCodeName(assertedType.Underlying())
|
||||
|
||||
+9
-15
@@ -70,7 +70,15 @@ func (b *builder) createMemoryCopyImpl() {
|
||||
// regular libc memset calls if they aren't optimized out in a different way.
|
||||
func (b *builder) createMemoryZeroImpl() {
|
||||
b.createFunctionStart(true)
|
||||
llvmFn := b.getMemsetFunc()
|
||||
fnName := "llvm.memset.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
||||
if llvmutil.Major() < 15 { // compatibility with LLVM 14
|
||||
fnName = "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
|
||||
}
|
||||
llvmFn := b.mod.NamedFunction(fnName)
|
||||
if llvmFn.IsNil() {
|
||||
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.ctx.Int8Type(), b.uintptrType, b.ctx.Int1Type()}, false)
|
||||
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
|
||||
}
|
||||
params := []llvm.Value{
|
||||
b.getValue(b.fn.Params[0], getPos(b.fn)),
|
||||
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
|
||||
@@ -81,20 +89,6 @@ func (b *builder) createMemoryZeroImpl() {
|
||||
b.CreateRetVoid()
|
||||
}
|
||||
|
||||
// Return the llvm.memset.p0.i8 function declaration.
|
||||
func (c *compilerContext) getMemsetFunc() llvm.Value {
|
||||
fnName := "llvm.memset.p0.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
|
||||
if llvmutil.Major() < 15 { // compatibility with LLVM 14
|
||||
fnName = "llvm.memset.p0i8.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
|
||||
}
|
||||
llvmFn := c.mod.NamedFunction(fnName)
|
||||
if llvmFn.IsNil() {
|
||||
fnType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType, c.ctx.Int8Type(), c.uintptrType, c.ctx.Int1Type()}, false)
|
||||
llvmFn = llvm.AddFunction(c.mod, fnName, fnType)
|
||||
}
|
||||
return llvmFn
|
||||
}
|
||||
|
||||
// createKeepAlive creates the runtime.KeepAlive function. It is implemented
|
||||
// using inline assembly.
|
||||
func (b *builder) createKeepAliveImpl() {
|
||||
|
||||
@@ -185,11 +185,6 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the given map.
|
||||
func (b *builder) createMapClear(m llvm.Value) {
|
||||
b.createRuntimeCall("hashmapClear", []llvm.Value{m}, "")
|
||||
}
|
||||
|
||||
// createMapIteratorNext lowers the *ssa.Next instruction for iterating over a
|
||||
// map. It returns a tuple of {bool, key, value} with the result of the
|
||||
// iteration.
|
||||
|
||||
+34
-74
@@ -4,7 +4,6 @@ package compiler
|
||||
// pragmas, determines the link name, etc.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
"go/types"
|
||||
@@ -23,9 +22,9 @@ import (
|
||||
// The linkName value contains a valid link name, even if //go:linkname is not
|
||||
// present.
|
||||
type functionInfo struct {
|
||||
wasmModule string // go:wasm-module
|
||||
wasmName string // wasm-export-name or wasm-import-name in the IR
|
||||
linkName string // go:linkname, go:export - the IR function name
|
||||
module string // go:wasm-module
|
||||
importName string // go:linkname, go:export - The name the developer assigns
|
||||
linkName string // go:linkname, go:export - The name that we map for the particular module -> importName
|
||||
section string // go:section - object file section name
|
||||
exported bool // go:export, CGo
|
||||
interrupt bool // go:interrupt
|
||||
@@ -194,14 +193,20 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
// External/exported functions may not retain pointer values.
|
||||
// https://golang.org/cmd/cgo/#hdr-Passing_pointers
|
||||
if info.exported {
|
||||
if c.archFamily() == "wasm32" && len(fn.Blocks) == 0 {
|
||||
if c.archFamily() == "wasm32" {
|
||||
// We need to add the wasm-import-module and the wasm-import-name
|
||||
// attributes.
|
||||
if info.wasmModule != "" {
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", info.wasmModule))
|
||||
module := info.module
|
||||
if module == "" {
|
||||
module = "env"
|
||||
}
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", module))
|
||||
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", info.wasmName))
|
||||
name := info.importName
|
||||
if name == "" {
|
||||
name = info.linkName
|
||||
}
|
||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", name))
|
||||
}
|
||||
nocaptureKind := llvm.AttributeKindID("nocapture")
|
||||
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
|
||||
@@ -234,26 +239,26 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||
// present in *ssa.Function, such as the link name and whether it should be
|
||||
// exported.
|
||||
func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
|
||||
if info, ok := c.functionInfos[f]; ok {
|
||||
return info
|
||||
}
|
||||
info := functionInfo{
|
||||
// Pick the default linkName.
|
||||
linkName: f.RelString(nil),
|
||||
}
|
||||
// Check for //go: pragmas, which may change the link name (among others).
|
||||
c.parsePragmas(&info, f)
|
||||
c.functionInfos[f] = info
|
||||
info.parsePragmas(f)
|
||||
return info
|
||||
}
|
||||
|
||||
// parsePragmas is used by getFunctionInfo to parse function pragmas such as
|
||||
// //export or //go:noinline.
|
||||
func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
func (info *functionInfo) parsePragmas(f *ssa.Function) {
|
||||
if f.Syntax() == nil {
|
||||
return
|
||||
}
|
||||
if decl, ok := f.Syntax().(*ast.FuncDecl); ok && decl.Doc != nil {
|
||||
|
||||
// Our importName for a wasm module (if we are compiling to wasm), or llvm link name
|
||||
var importName string
|
||||
|
||||
for _, comment := range decl.Doc.List {
|
||||
text := comment.Text
|
||||
if strings.HasPrefix(text, "//export ") {
|
||||
@@ -271,8 +276,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
continue
|
||||
}
|
||||
|
||||
info.linkName = parts[1]
|
||||
info.wasmName = info.linkName
|
||||
importName = parts[1]
|
||||
info.exported = true
|
||||
case "//go:interrupt":
|
||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||
@@ -280,22 +284,19 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
}
|
||||
case "//go:wasm-module":
|
||||
// Alternative comment for setting the import module.
|
||||
// This is deprecated, use //go:wasmimport instead.
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
info.wasmModule = parts[1]
|
||||
info.module = parts[1]
|
||||
case "//go:wasmimport":
|
||||
// Import a WebAssembly function, for example a WASI function.
|
||||
// Original proposal: https://github.com/golang/go/issues/38248
|
||||
// Allow globally: https://github.com/golang/go/issues/59149
|
||||
if len(parts) != 3 {
|
||||
// For details, see: https://github.com/golang/go/issues/38248
|
||||
if len(parts) != 3 || len(f.Blocks) != 0 {
|
||||
continue
|
||||
}
|
||||
c.checkWasmImport(f, comment.Text)
|
||||
info.exported = true
|
||||
info.wasmModule = parts[1]
|
||||
info.wasmName = parts[2]
|
||||
info.module = parts[1]
|
||||
info.importName = parts[2]
|
||||
case "//go:inline":
|
||||
info.inline = inlineHint
|
||||
case "//go:noinline":
|
||||
@@ -339,59 +340,18 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether this function cannot be used in //go:wasmimport. It will add an
|
||||
// error if this is the case.
|
||||
//
|
||||
// The list of allowed types is based on this proposal:
|
||||
// https://github.com/golang/go/issues/59149
|
||||
func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
|
||||
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" {
|
||||
// The runtime is a special case. Allow all kinds of parameters
|
||||
// (importantly, including pointers).
|
||||
return
|
||||
}
|
||||
if f.Blocks != nil {
|
||||
// Defined functions cannot be exported.
|
||||
c.addError(f.Pos(), fmt.Sprintf("can only use //go:wasmimport on declarations"))
|
||||
return
|
||||
}
|
||||
if f.Signature.Results().Len() > 1 {
|
||||
c.addError(f.Signature.Results().At(1).Pos(), fmt.Sprintf("%s: too many return values", pragma))
|
||||
} else if f.Signature.Results().Len() == 1 {
|
||||
result := f.Signature.Results().At(0)
|
||||
if !isValidWasmType(result.Type(), true) {
|
||||
c.addError(result.Pos(), fmt.Sprintf("%s: unsupported result type %s", pragma, result.Type().String()))
|
||||
}
|
||||
}
|
||||
for _, param := range f.Params {
|
||||
// Check whether the type is allowed.
|
||||
// Only a very limited number of types can be mapped to WebAssembly.
|
||||
if !isValidWasmType(param.Type(), false) {
|
||||
c.addError(param.Pos(), fmt.Sprintf("%s: unsupported parameter type %s", pragma, param.Type().String()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether the type maps directly to a WebAssembly type, according to:
|
||||
// https://github.com/golang/go/issues/59149
|
||||
func isValidWasmType(typ types.Type, isReturn bool) bool {
|
||||
switch typ := typ.Underlying().(type) {
|
||||
case *types.Basic:
|
||||
switch typ.Kind() {
|
||||
case types.Int32, types.Uint32, types.Int64, types.Uint64:
|
||||
return true
|
||||
case types.Float32, types.Float64:
|
||||
return true
|
||||
case types.UnsafePointer:
|
||||
if !isReturn {
|
||||
return true
|
||||
// Set the importName for our exported function if we have one
|
||||
if importName != "" {
|
||||
if info.module == "" {
|
||||
info.linkName = importName
|
||||
} else {
|
||||
// WebAssembly import
|
||||
info.importName = importName
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// getParams returns the function parameters, including the receiver at the
|
||||
@@ -457,7 +417,7 @@ func (c *compilerContext) addStandardDefinedAttributes(llvmFn llvm.Value) {
|
||||
}
|
||||
}
|
||||
|
||||
// addStandardAttributes adds all attributes added to defined functions.
|
||||
// addStandardAttribute adds all attributes added to defined functions.
|
||||
func (c *compilerContext) addStandardAttributes(llvmFn llvm.Value) {
|
||||
c.addStandardDeclaredAttributes(llvmFn)
|
||||
c.addStandardDefinedAttributes(llvmFn)
|
||||
|
||||
+8
-20
@@ -37,16 +37,9 @@ entry:
|
||||
|
||||
1: ; preds = %entry
|
||||
call void @main.external(ptr undef) #4
|
||||
br label %rundefers.block
|
||||
|
||||
rundefers.after: ; preds = %rundefers.end
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
rundefers.block: ; preds = %1
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.loophead: ; preds = %3, %rundefers.block
|
||||
rundefers.loophead: ; preds = %3, %1
|
||||
%2 = load ptr, ptr %deferPtr, align 4
|
||||
%stackIsNil = icmp eq ptr %2, null
|
||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||
@@ -73,7 +66,8 @@ rundefers.default: ; preds = %rundefers.loop
|
||||
unreachable
|
||||
|
||||
rundefers.end: ; preds = %rundefers.loophead
|
||||
br label %rundefers.after
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
recover: ; preds = %rundefers.end3
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
@@ -117,8 +111,6 @@ declare ptr @llvm.stacksave() #3
|
||||
|
||||
declare void @runtime.setupDeferFrame(ptr dereferenceable_or_null(24), ptr, ptr) #2
|
||||
|
||||
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define internal void @"main.deferSimple$1"(ptr %context) unnamed_addr #1 {
|
||||
entry:
|
||||
@@ -126,6 +118,8 @@ entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.destroyDeferFrame(ptr dereferenceable_or_null(24), ptr) #2
|
||||
|
||||
declare void @runtime.printint32(i32, ptr) #2
|
||||
|
||||
; Function Attrs: nounwind
|
||||
@@ -152,16 +146,9 @@ entry:
|
||||
|
||||
1: ; preds = %entry
|
||||
call void @main.external(ptr undef) #4
|
||||
br label %rundefers.block
|
||||
|
||||
rundefers.after: ; preds = %rundefers.end
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
rundefers.block: ; preds = %1
|
||||
br label %rundefers.loophead
|
||||
|
||||
rundefers.loophead: ; preds = %4, %3, %rundefers.block
|
||||
rundefers.loophead: ; preds = %4, %3, %1
|
||||
%2 = load ptr, ptr %deferPtr, align 4
|
||||
%stackIsNil = icmp eq ptr %2, null
|
||||
br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop
|
||||
@@ -198,7 +185,8 @@ rundefers.default: ; preds = %rundefers.loop
|
||||
unreachable
|
||||
|
||||
rundefers.end: ; preds = %rundefers.loophead
|
||||
br label %rundefers.after
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
ret void
|
||||
|
||||
recover: ; preds = %rundefers.end7
|
||||
call void @runtime.destroyDeferFrame(ptr nonnull %deferframe.buf, ptr undef) #4
|
||||
|
||||
Vendored
-43
@@ -1,43 +0,0 @@
|
||||
package main
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//go:wasmimport modulename empty
|
||||
func empty()
|
||||
|
||||
// ERROR: can only use //go:wasmimport on declarations
|
||||
//
|
||||
//go:wasmimport modulename implementation
|
||||
func implementation() {
|
||||
}
|
||||
|
||||
type Uint uint32
|
||||
|
||||
//go:wasmimport modulename validparam
|
||||
func validparam(a int32, b uint64, c float64, d unsafe.Pointer, e Uint)
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type int
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type string
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type []byte
|
||||
// ERROR: //go:wasmimport modulename invalidparam: unsupported parameter type *int32
|
||||
//
|
||||
//go:wasmimport modulename invalidparam
|
||||
func invalidparam(a int, b string, c []byte, d *int32)
|
||||
|
||||
//go:wasmimport modulename validreturn
|
||||
func validreturn() int32
|
||||
|
||||
// ERROR: //go:wasmimport modulename manyreturns: too many return values
|
||||
//
|
||||
//go:wasmimport modulename manyreturns
|
||||
func manyreturns() (int32, int32)
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidreturn: unsupported result type int
|
||||
//
|
||||
//go:wasmimport modulename invalidreturn
|
||||
func invalidreturn() int
|
||||
|
||||
// ERROR: //go:wasmimport modulename invalidUnsafePointerReturn: unsupported result type unsafe.Pointer
|
||||
//
|
||||
//go:wasmimport modulename invalidUnsafePointerReturn
|
||||
func invalidUnsafePointerReturn() unsafe.Pointer
|
||||
Vendored
+2
-2
@@ -21,8 +21,8 @@ target triple = "wasm32-unknown-wasi"
|
||||
@main.slice3 = hidden global { ptr, i32, i32 } zeroinitializer, align 8
|
||||
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
|
||||
@"runtime/gc.layout:62-0001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00\00" }
|
||||
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 80, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
|
||||
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
|
||||
@"reflect/types.type:basic:complex128" = linkonce_odr constant { i8, ptr } { i8 16, ptr @"reflect/types.type:pointer:basic:complex128" }, align 4
|
||||
@"reflect/types.type:pointer:basic:complex128" = linkonce_odr constant { i8, i16, ptr } { i8 21, i16 0, ptr @"reflect/types.type:basic:complex128" }, align 4
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
Vendored
-65
@@ -1,65 +0,0 @@
|
||||
package main
|
||||
|
||||
func min1(a int) int {
|
||||
return min(a)
|
||||
}
|
||||
|
||||
func min2(a, b int) int {
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func min3(a, b, c int) int {
|
||||
return min(a, b, c)
|
||||
}
|
||||
|
||||
func min4(a, b, c, d int) int {
|
||||
return min(a, b, c, d)
|
||||
}
|
||||
|
||||
func minUint8(a, b uint8) uint8 {
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func minUnsigned(a, b uint) uint {
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func minFloat32(a, b float32) float32 {
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func minFloat64(a, b float64) float64 {
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func minString(a, b string) string {
|
||||
return min(a, b)
|
||||
}
|
||||
|
||||
func maxInt(a, b int) int {
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
func maxUint(a, b uint) uint {
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
func maxFloat32(a, b float32) float32 {
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
func maxString(a, b string) string {
|
||||
return max(a, b)
|
||||
}
|
||||
|
||||
func clearSlice(s []int) {
|
||||
clear(s)
|
||||
}
|
||||
|
||||
func clearZeroSizedSlice(s []struct{}) {
|
||||
clear(s)
|
||||
}
|
||||
|
||||
func clearMap(m map[string]int) {
|
||||
clear(m)
|
||||
}
|
||||
Vendored
-179
@@ -1,179 +0,0 @@
|
||||
; ModuleID = 'go1.21.go'
|
||||
source_filename = "go1.21.go"
|
||||
target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-n32:64-S128-ni:1:10:20"
|
||||
target triple = "wasm32-unknown-wasi"
|
||||
|
||||
%runtime._string = type { ptr, i32 }
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
declare noalias nonnull ptr @runtime.alloc(i32, ptr, ptr) #0
|
||||
|
||||
declare void @runtime.trackPointer(ptr nocapture readonly, ptr, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.init(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min1(i32 %a, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret i32 %a
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min2(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min3(i32 %a, i32 %b, i32 %c, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
|
||||
ret i32 %1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.min4(i32 %a, i32 %b, i32 %c, i32 %d, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smin.i32(i32 %a, i32 %b)
|
||||
%1 = call i32 @llvm.smin.i32(i32 %0, i32 %c)
|
||||
%2 = call i32 @llvm.smin.i32(i32 %1, i32 %d)
|
||||
ret i32 %2
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i8 @main.minUint8(i8 %a, i8 %b, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i8 @llvm.umin.i8(i8 %a, i8 %b)
|
||||
ret i8 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.minUnsigned(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.umin.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.minFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fcmp olt float %a, %b
|
||||
%1 = select i1 %0, float %a, float %b
|
||||
ret float %1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden double @main.minFloat64(double %a, double %b, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fcmp olt double %a, %b
|
||||
%1 = select i1 %0, double %a, double %b
|
||||
ret double %1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.minString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
|
||||
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
|
||||
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
|
||||
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
|
||||
%stackalloc = alloca i8, align 1
|
||||
%4 = call i1 @runtime.stringLess(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr undef) #5
|
||||
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
|
||||
%6 = extractvalue %runtime._string %5, 0
|
||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret %runtime._string %5
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringLess(ptr, i32, ptr, i32, ptr) #1
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.maxInt(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.smax.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden i32 @main.maxUint(i32 %a, i32 %b, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = call i32 @llvm.umax.i32(i32 %a, i32 %b)
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden float @main.maxFloat32(float %a, float %b, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = fcmp ogt float %a, %b
|
||||
%1 = select i1 %0, float %a, float %b
|
||||
ret float %1
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden %runtime._string @main.maxString(ptr %a.data, i32 %a.len, ptr %b.data, i32 %b.len, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = insertvalue %runtime._string zeroinitializer, ptr %a.data, 0
|
||||
%1 = insertvalue %runtime._string %0, i32 %a.len, 1
|
||||
%2 = insertvalue %runtime._string zeroinitializer, ptr %b.data, 0
|
||||
%3 = insertvalue %runtime._string %2, i32 %b.len, 1
|
||||
%stackalloc = alloca i8, align 1
|
||||
%4 = call i1 @runtime.stringLess(ptr %b.data, i32 %b.len, ptr %a.data, i32 %a.len, ptr undef) #5
|
||||
%5 = select i1 %4, %runtime._string %1, %runtime._string %3
|
||||
%6 = extractvalue %runtime._string %5, 0
|
||||
call void @runtime.trackPointer(ptr %6, ptr nonnull %stackalloc, ptr undef) #5
|
||||
ret %runtime._string %5
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.clearSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
%0 = shl i32 %s.len, 2
|
||||
call void @llvm.memset.p0.i32(ptr align 4 %s.data, i8 0, i32 %0, i1 false)
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: argmemonly nocallback nofree nounwind willreturn writeonly
|
||||
declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1 immarg) #3
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.clearZeroSizedSlice(ptr %s.data, i32 %s.len, i32 %s.cap, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define hidden void @main.clearMap(ptr dereferenceable_or_null(40) %m, ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
call void @runtime.hashmapClear(ptr %m, ptr undef) #5
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.hashmapClear(ptr dereferenceable_or_null(40), ptr) #1
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
||||
declare i32 @llvm.smin.i32(i32, i32) #4
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
||||
declare i8 @llvm.umin.i8(i8, i8) #4
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
||||
declare i32 @llvm.umin.i32(i32, i32) #4
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
||||
declare i32 @llvm.smax.i32(i32, i32) #4
|
||||
|
||||
; Function Attrs: nocallback nofree nosync nounwind readnone speculatable willreturn
|
||||
declare i32 @llvm.umax.i32(i32, i32) #4
|
||||
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { argmemonly nocallback nofree nounwind willreturn writeonly }
|
||||
attributes #4 = { nocallback nofree nosync nounwind readnone speculatable willreturn }
|
||||
attributes #5 = { nounwind }
|
||||
Vendored
+8
-8
@@ -6,15 +6,15 @@ target triple = "wasm32-unknown-wasi"
|
||||
%runtime._interface = type { ptr, ptr }
|
||||
%runtime._string = type { ptr, i32 }
|
||||
|
||||
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 -62, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:named:error" }, align 4
|
||||
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 116, i16 0, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
|
||||
@"reflect/types.type:basic:int" = linkonce_odr constant { i8, ptr } { i8 2, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant { i8, i16, ptr } { i8 21, i16 0, ptr @"reflect/types.type:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:named:error" = linkonce_odr constant { i8, i16, ptr } { i8 21, i16 0, ptr @"reflect/types.type:named:error" }, align 4
|
||||
@"reflect/types.type:named:error" = linkonce_odr constant { i8, i16, ptr, ptr, ptr, [7 x i8] } { i8 52, i16 1, ptr @"reflect/types.type:pointer:named:error", ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}", ptr @"reflect/types.type.pkgpath.empty", [7 x i8] c".error\00" }, align 4
|
||||
@"reflect/types.type.pkgpath.empty" = linkonce_odr unnamed_addr constant [1 x i8] zeroinitializer, align 1
|
||||
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 -43, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 84, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 20, ptr @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 21, i16 0, ptr @"reflect/types.type:interface:{Error:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, i16, ptr } { i8 21, i16 0, ptr @"reflect/types.type:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant { i8, ptr } { i8 20, ptr @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }, align 4
|
||||
@"reflect/types.typeid:basic:int" = external constant i8
|
||||
|
||||
; Function Attrs: allockind("alloc,zeroed") allocsize(0)
|
||||
|
||||
Vendored
+2
-11
@@ -62,17 +62,8 @@ func exportedFunctionInSection() {
|
||||
//go:wasmimport modulename import1
|
||||
func declaredImport()
|
||||
|
||||
// Legacy way of importing a function.
|
||||
//
|
||||
//go:wasm-module foobar
|
||||
//export imported
|
||||
func foobarImport()
|
||||
|
||||
// The wasm-module pragma is not functional here, but it should be safe.
|
||||
//
|
||||
//go:wasm-module foobar
|
||||
//export exported
|
||||
func foobarExportModule() {
|
||||
//go:wasmimport modulename import2
|
||||
func definedImport() {
|
||||
}
|
||||
|
||||
// This function should not: it's only a declaration and not a definition.
|
||||
|
||||
Vendored
+4
-8
@@ -6,7 +6,7 @@ target triple = "wasm32-unknown-wasi"
|
||||
@extern_global = external global [0 x i8], align 1
|
||||
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
|
||||
@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16
|
||||
@llvm.used = appending global [3 x ptr] [ptr @extern_func, ptr @exportedFunctionInSection, ptr @exported]
|
||||
@llvm.used = appending global [2 x ptr] [ptr @extern_func, ptr @exportedFunctionInSection]
|
||||
@main.globalInSection = hidden global i32 0, section ".special_global_section", align 4
|
||||
@undefinedGlobalNotInSection = external global i32, align 4
|
||||
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
|
||||
@@ -62,10 +62,8 @@ entry:
|
||||
|
||||
declare void @main.declaredImport() #7
|
||||
|
||||
declare void @imported() #8
|
||||
|
||||
; Function Attrs: nounwind
|
||||
define void @exported() #9 {
|
||||
define hidden void @main.definedImport(ptr %context) unnamed_addr #2 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
@@ -75,10 +73,8 @@ declare void @main.undefinedFunctionNotInSection(ptr) #1
|
||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" }
|
||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" }
|
||||
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" }
|
||||
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" }
|
||||
attributes #7 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
||||
attributes #8 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
|
||||
attributes #9 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exported" }
|
||||
|
||||
@@ -13,8 +13,7 @@ require (
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
|
||||
github.com/mattn/go-colorable v0.1.8
|
||||
github.com/mattn/go-tty v0.0.4
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3
|
||||
go.bug.st/serial v1.6.0
|
||||
go.bug.st/serial v1.3.5
|
||||
golang.org/x/sys v0.4.0
|
||||
golang.org/x/tools v0.5.1-0.20230114154351-e035d0c426c8
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
|
||||
@@ -12,8 +12,6 @@ github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moA
|
||||
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
|
||||
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/deadprogram/go-serial v0.0.0-20230717164825-4529b3232919 h1:Hi7G1bCG70NwlyqGswJKEHoIi4hJVN1SsmfwZ+DQHtw=
|
||||
github.com/deadprogram/go-serial v0.0.0-20230717164825-4529b3232919/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||
@@ -45,11 +43,9 @@ github.com/mattn/go-tty v0.0.4/go.mod h1:u5GGXBtZU6RQoKV8gY5W6UhMudbR5vXnUe7j3px
|
||||
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5 h1:1SoBaSPudixRecmlHXb/GxmaD3fLMtHIDN13QujwQuc=
|
||||
github.com/orisano/pixelmatch v0.0.0-20210112091706-4fa4c7ba91d5/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs=
|
||||
github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
go.bug.st/serial v1.6.0 h1:mAbRGN4cKE2J5gMwsMHC2KQisdLRQssO9WSM+rbZJ8A=
|
||||
go.bug.st/serial v1.6.0/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
|
||||
go.bug.st/serial v1.3.5 h1:k50SqGZCnHZ2MiBQgzccXWG+kd/XpOs1jUljpDDKzaE=
|
||||
go.bug.st/serial v1.3.5/go.mod h1:z8CesKorE90Qr/oRSJiEuvzYRKol9r/anJZEb5kt304=
|
||||
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
||||
+99
-53
@@ -4,16 +4,15 @@ package goenv
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Keys is a slice of all available environment variable keys.
|
||||
@@ -38,53 +37,6 @@ func init() {
|
||||
// directory.
|
||||
var TINYGOROOT string
|
||||
|
||||
// Variables read from a `go env` command invocation.
|
||||
var goEnvVars struct {
|
||||
GOPATH string
|
||||
GOROOT string
|
||||
GOVERSION string
|
||||
}
|
||||
|
||||
var goEnvVarsOnce sync.Once
|
||||
var goEnvVarsErr error // error returned from cmd.Run
|
||||
|
||||
// Make sure goEnvVars is fresh. This can be called multiple times, the first
|
||||
// time will update all environment variables in goEnvVars.
|
||||
func readGoEnvVars() error {
|
||||
goEnvVarsOnce.Do(func() {
|
||||
cmd := exec.Command("go", "env", "-json", "GOPATH", "GOROOT", "GOVERSION")
|
||||
output, err := cmd.Output()
|
||||
if err != nil {
|
||||
// Check for "command not found" error.
|
||||
if execErr, ok := err.(*exec.Error); ok {
|
||||
goEnvVarsErr = fmt.Errorf("could not find '%s' command: %w", execErr.Name, execErr.Err)
|
||||
return
|
||||
}
|
||||
// It's perhaps a bit ugly to handle this error here, but I couldn't
|
||||
// think of a better place further up in the call chain.
|
||||
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() != 0 {
|
||||
if len(exitErr.Stderr) != 0 {
|
||||
// The 'go' command exited with an error message. Print that
|
||||
// message and exit, so we behave in a similar way.
|
||||
os.Stderr.Write(exitErr.Stderr)
|
||||
os.Exit(exitErr.ExitCode())
|
||||
}
|
||||
}
|
||||
// Other errors. Not sure whether there are any, but just in case.
|
||||
goEnvVarsErr = err
|
||||
return
|
||||
}
|
||||
err = json.Unmarshal(output, &goEnvVars)
|
||||
if err != nil {
|
||||
// This should never happen if we have a sane Go toolchain
|
||||
// installed.
|
||||
goEnvVarsErr = fmt.Errorf("unexpected error while unmarshalling `go env` output: %w", err)
|
||||
}
|
||||
})
|
||||
|
||||
return goEnvVarsErr
|
||||
}
|
||||
|
||||
// Get returns a single environment variable, possibly calculating it on-demand.
|
||||
// The empty string is returned for unknown environment variables.
|
||||
func Get(name string) string {
|
||||
@@ -118,11 +70,15 @@ func Get(name string) string {
|
||||
// especially when floating point instructions are involved.
|
||||
return "6"
|
||||
case "GOROOT":
|
||||
readGoEnvVars()
|
||||
return goEnvVars.GOROOT
|
||||
return getGoroot()
|
||||
case "GOPATH":
|
||||
readGoEnvVars()
|
||||
return goEnvVars.GOPATH
|
||||
if dir := os.Getenv("GOPATH"); dir != "" {
|
||||
return dir
|
||||
}
|
||||
|
||||
// fallback
|
||||
home := getHomeDir()
|
||||
return filepath.Join(home, "go")
|
||||
case "GOCACHE":
|
||||
// Get the cache directory, usually ~/.cache/tinygo
|
||||
dir, err := os.UserCacheDir()
|
||||
@@ -284,3 +240,93 @@ func isSourceDir(root string) bool {
|
||||
_, err = os.Stat(filepath.Join(root, "src/device/arm/arm.go"))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func getHomeDir() string {
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
panic("cannot get current user: " + err.Error())
|
||||
}
|
||||
if u.HomeDir == "" {
|
||||
// This is very unlikely, so panic here.
|
||||
// Not the nicest solution, however.
|
||||
panic("could not find home directory")
|
||||
}
|
||||
return u.HomeDir
|
||||
}
|
||||
|
||||
// getGoroot returns an appropriate GOROOT from various sources. If it can't be
|
||||
// found, it returns an empty string.
|
||||
func getGoroot() string {
|
||||
// An explicitly set GOROOT always has preference.
|
||||
goroot := os.Getenv("GOROOT")
|
||||
if goroot != "" {
|
||||
// Convert to the standard GOROOT being referenced, if it's a TinyGo cache.
|
||||
return getStandardGoroot(goroot)
|
||||
}
|
||||
|
||||
// Check for the location of the 'go' binary and base GOROOT on that.
|
||||
binpath, err := exec.LookPath("go")
|
||||
if err == nil {
|
||||
binpath, err = filepath.EvalSymlinks(binpath)
|
||||
if err == nil {
|
||||
goroot := filepath.Dir(filepath.Dir(binpath))
|
||||
if isGoroot(goroot) {
|
||||
return goroot
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check what GOROOT was at compile time.
|
||||
if isGoroot(runtime.GOROOT()) {
|
||||
return runtime.GOROOT()
|
||||
}
|
||||
|
||||
// Check for some standard locations, as a last resort.
|
||||
var candidates []string
|
||||
switch runtime.GOOS {
|
||||
case "linux":
|
||||
candidates = []string{
|
||||
"/usr/local/go", // manually installed
|
||||
"/usr/lib/go", // from the distribution
|
||||
"/snap/go/current/", // installed using snap
|
||||
}
|
||||
case "darwin":
|
||||
candidates = []string{
|
||||
"/usr/local/go", // manually installed
|
||||
"/usr/local/opt/go/libexec", // from Homebrew
|
||||
}
|
||||
}
|
||||
|
||||
for _, candidate := range candidates {
|
||||
if isGoroot(candidate) {
|
||||
return candidate
|
||||
}
|
||||
}
|
||||
|
||||
// Can't find GOROOT...
|
||||
return ""
|
||||
}
|
||||
|
||||
// isGoroot checks whether the given path looks like a GOROOT.
|
||||
func isGoroot(goroot string) bool {
|
||||
_, err := os.Stat(filepath.Join(goroot, "src", "runtime", "internal", "sys", "zversion.go"))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// getStandardGoroot returns the physical path to a real, standard Go GOROOT
|
||||
// implied by the given path.
|
||||
// If the given path appears to be a TinyGo cached GOROOT, it returns the path
|
||||
// referenced by symlinks contained in the cache. Otherwise, it returns the
|
||||
// given path as-is.
|
||||
func getStandardGoroot(path string) string {
|
||||
// Check if the "bin" subdirectory of our given GOROOT is a symlink, and then
|
||||
// return the _parent_ directory of its destination.
|
||||
if dest, err := os.Readlink(filepath.Join(path, "bin")); nil == err {
|
||||
// Clean the destination to remove any trailing slashes, so that
|
||||
// filepath.Dir will always return the parent.
|
||||
// (because both "/foo" and "/foo/" are valid symlink destinations,
|
||||
// but filepath.Dir would return "/" and "/foo", respectively)
|
||||
return filepath.Dir(filepath.Clean(dest))
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
+26
-8
@@ -4,12 +4,15 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const Version = "0.29.0"
|
||||
const Version = "0.28.0-dev"
|
||||
|
||||
var (
|
||||
// This variable is set at build time using -ldflags parameters.
|
||||
@@ -19,8 +22,8 @@ var (
|
||||
|
||||
// GetGorootVersion returns the major and minor version for a given GOROOT path.
|
||||
// If the goroot cannot be determined, (0, 0) is returned.
|
||||
func GetGorootVersion() (major, minor int, err error) {
|
||||
s, err := GorootVersionString()
|
||||
func GetGorootVersion(goroot string) (major, minor int, err error) {
|
||||
s, err := GorootVersionString(goroot)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
@@ -48,9 +51,24 @@ func GetGorootVersion() (major, minor int, err error) {
|
||||
}
|
||||
|
||||
// GorootVersionString returns the version string as reported by the Go
|
||||
// toolchain. It is usually of the form `go1.x.y` but can have some variations
|
||||
// (for beta releases, for example).
|
||||
func GorootVersionString() (string, error) {
|
||||
err := readGoEnvVars()
|
||||
return goEnvVars.GOVERSION, err
|
||||
// toolchain for the given GOROOT path. It is usually of the form `go1.x.y` but
|
||||
// can have some variations (for beta releases, for example).
|
||||
func GorootVersionString(goroot string) (string, error) {
|
||||
if data, err := os.ReadFile(filepath.Join(goroot, "VERSION")); err == nil {
|
||||
return string(data), nil
|
||||
|
||||
} else if data, err := os.ReadFile(filepath.Join(
|
||||
goroot, "src", "internal", "buildcfg", "zbootstrap.go")); err == nil {
|
||||
|
||||
r := regexp.MustCompile("const version = `(.*)`")
|
||||
matches := r.FindSubmatch(data)
|
||||
if len(matches) != 2 {
|
||||
return "", errors.New("Invalid go version output:\n" + string(data))
|
||||
}
|
||||
|
||||
return string(matches[1]), nil
|
||||
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
+57
-20
@@ -346,7 +346,16 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
dstObj.buffer = dstBuf
|
||||
mem.put(dst.index(), dstObj)
|
||||
}
|
||||
locals[inst.localIndex] = makeLiteralInt(n, inst.llvmInst.Type().IntTypeWidth())
|
||||
switch inst.llvmInst.Type().IntTypeWidth() {
|
||||
case 16:
|
||||
locals[inst.localIndex] = literalValue{uint16(n)}
|
||||
case 32:
|
||||
locals[inst.localIndex] = literalValue{uint32(n)}
|
||||
case 64:
|
||||
locals[inst.localIndex] = literalValue{uint64(n)}
|
||||
default:
|
||||
panic("unknown integer type width")
|
||||
}
|
||||
case strings.HasPrefix(callFn.name, "llvm.memcpy.p0") || strings.HasPrefix(callFn.name, "llvm.memmove.p0"):
|
||||
// Copy a block of memory from one pointer to another.
|
||||
dst, err := operands[1].asPointer(r)
|
||||
@@ -638,7 +647,16 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
}
|
||||
// GEP on fixed pointer value (for example, memory-mapped I/O).
|
||||
ptrValue := operands[0].Uint() + offset
|
||||
locals[inst.localIndex] = makeLiteralInt(ptrValue, int(operands[0].len(r)*8))
|
||||
switch operands[0].len(r) {
|
||||
case 8:
|
||||
locals[inst.localIndex] = literalValue{uint64(ptrValue)}
|
||||
case 4:
|
||||
locals[inst.localIndex] = literalValue{uint32(ptrValue)}
|
||||
case 2:
|
||||
locals[inst.localIndex] = literalValue{uint16(ptrValue)}
|
||||
default:
|
||||
panic("pointer operand is not of a known pointer size")
|
||||
}
|
||||
continue
|
||||
}
|
||||
ptr = ptr.addOffset(int64(offset))
|
||||
@@ -736,33 +754,30 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
if err == nil {
|
||||
// The lhs is a pointer. This sometimes happens for particular
|
||||
// pointer tricks.
|
||||
if inst.opcode == llvm.Add {
|
||||
switch inst.opcode {
|
||||
case llvm.Add:
|
||||
// This likely means this is part of a
|
||||
// unsafe.Pointer(uintptr(ptr) + offset) pattern.
|
||||
lhsPtr = lhsPtr.addOffset(int64(rhs.Uint()))
|
||||
locals[inst.localIndex] = lhsPtr
|
||||
} else if inst.opcode == llvm.Xor && rhs.Uint() == 0 {
|
||||
// Special workaround for strings.noescape, see
|
||||
// src/strings/builder.go in the Go source tree. This is
|
||||
// the identity operator, so we can return the input.
|
||||
locals[inst.localIndex] = lhs
|
||||
} else if inst.opcode == llvm.And && rhs.Uint() < 8 {
|
||||
// This is probably part of a pattern to get the lower bits
|
||||
// of a pointer for pointer tagging, like this:
|
||||
// uintptr(unsafe.Pointer(t)) & 0b11
|
||||
// We can actually support this easily by ANDing with the
|
||||
// pointer offset.
|
||||
result := uint64(lhsPtr.offset()) & rhs.Uint()
|
||||
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
|
||||
} else {
|
||||
continue
|
||||
case llvm.Xor:
|
||||
if rhs.Uint() == 0 {
|
||||
// Special workaround for strings.noescape, see
|
||||
// src/strings/builder.go in the Go source tree. This is
|
||||
// the identity operator, so we can return the input.
|
||||
locals[inst.localIndex] = lhs
|
||||
continue
|
||||
}
|
||||
default:
|
||||
// Catch-all for weird operations that should just be done
|
||||
// at runtime.
|
||||
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
|
||||
if err != nil {
|
||||
return nil, mem, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
continue
|
||||
}
|
||||
var result uint64
|
||||
switch inst.opcode {
|
||||
@@ -795,7 +810,18 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
locals[inst.localIndex] = makeLiteralInt(result, int(lhs.len(r)*8))
|
||||
switch lhs.len(r) {
|
||||
case 8:
|
||||
locals[inst.localIndex] = literalValue{result}
|
||||
case 4:
|
||||
locals[inst.localIndex] = literalValue{uint32(result)}
|
||||
case 2:
|
||||
locals[inst.localIndex] = literalValue{uint16(result)}
|
||||
case 1:
|
||||
locals[inst.localIndex] = literalValue{uint8(result)}
|
||||
default:
|
||||
panic("unknown integer size")
|
||||
}
|
||||
if r.debug {
|
||||
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", lhs, rhs, "->", result)
|
||||
}
|
||||
@@ -817,7 +843,18 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
if r.debug {
|
||||
fmt.Fprintln(os.Stderr, indent+instructionNameMap[inst.opcode]+":", value, bitwidth)
|
||||
}
|
||||
locals[inst.localIndex] = makeLiteralInt(value, int(bitwidth))
|
||||
switch bitwidth {
|
||||
case 64:
|
||||
locals[inst.localIndex] = literalValue{value}
|
||||
case 32:
|
||||
locals[inst.localIndex] = literalValue{uint32(value)}
|
||||
case 16:
|
||||
locals[inst.localIndex] = literalValue{uint16(value)}
|
||||
case 8:
|
||||
locals[inst.localIndex] = literalValue{uint8(value)}
|
||||
default:
|
||||
panic("unknown integer size in sext/zext/trunc")
|
||||
}
|
||||
case llvm.SIToFP, llvm.UIToFP:
|
||||
var value float64
|
||||
switch inst.opcode {
|
||||
|
||||
@@ -373,22 +373,6 @@ type literalValue struct {
|
||||
value interface{}
|
||||
}
|
||||
|
||||
// Make a literalValue given the number of bits.
|
||||
func makeLiteralInt(value uint64, bits int) literalValue {
|
||||
switch bits {
|
||||
case 64:
|
||||
return literalValue{value}
|
||||
case 32:
|
||||
return literalValue{uint32(value)}
|
||||
case 16:
|
||||
return literalValue{uint16(value)}
|
||||
case 8:
|
||||
return literalValue{uint8(value)}
|
||||
default:
|
||||
panic("unknown integer size")
|
||||
}
|
||||
}
|
||||
|
||||
func (v literalValue) len(r *runner) uint32 {
|
||||
switch v.value.(type) {
|
||||
case uint64:
|
||||
|
||||
Vendored
+28
-28
@@ -2,17 +2,17 @@ target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32--wasi"
|
||||
|
||||
@"runtime/gc.layout:62-2000000000000001" = linkonce_odr unnamed_addr constant { i32, [8 x i8] } { i32 62, [8 x i8] c"\01\00\00\00\00\00\00 " }
|
||||
@pointerFree12 = global ptr null
|
||||
@pointerFree7 = global ptr null
|
||||
@pointerFree3 = global ptr null
|
||||
@pointerFree0 = global ptr null
|
||||
@layout1 = global ptr null
|
||||
@layout2 = global ptr null
|
||||
@layout3 = global ptr null
|
||||
@layout4 = global ptr null
|
||||
@bigobj1 = global ptr null
|
||||
@pointerFree12 = global i8* null
|
||||
@pointerFree7 = global i8* null
|
||||
@pointerFree3 = global i8* null
|
||||
@pointerFree0 = global i8* null
|
||||
@layout1 = global i8* null
|
||||
@layout2 = global i8* null
|
||||
@layout3 = global i8* null
|
||||
@layout4 = global i8* null
|
||||
@bigobj1 = global i8* null
|
||||
|
||||
declare ptr @runtime.alloc(i32, ptr) unnamed_addr
|
||||
declare i8* @runtime.alloc(i32, i8*) unnamed_addr
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
call void @main.init()
|
||||
@@ -21,33 +21,33 @@ define void @runtime.initAll() unnamed_addr {
|
||||
|
||||
define internal void @main.init() unnamed_addr {
|
||||
; Object that's word-aligned.
|
||||
%pointerFree12 = call ptr @runtime.alloc(i32 12, ptr inttoptr (i32 3 to ptr))
|
||||
store ptr %pointerFree12, ptr @pointerFree12
|
||||
%pointerFree12 = call i8* @runtime.alloc(i32 12, i8* inttoptr (i32 3 to i8*))
|
||||
store i8* %pointerFree12, i8** @pointerFree12
|
||||
; Object larger than a word but not word-aligned.
|
||||
%pointerFree7 = call ptr @runtime.alloc(i32 7, ptr inttoptr (i32 3 to ptr))
|
||||
store ptr %pointerFree7, ptr @pointerFree7
|
||||
%pointerFree7 = call i8* @runtime.alloc(i32 7, i8* inttoptr (i32 3 to i8*))
|
||||
store i8* %pointerFree7, i8** @pointerFree7
|
||||
; Object smaller than a word (and of course not word-aligned).
|
||||
%pointerFree3 = call ptr @runtime.alloc(i32 3, ptr inttoptr (i32 3 to ptr))
|
||||
store ptr %pointerFree3, ptr @pointerFree3
|
||||
%pointerFree3 = call i8* @runtime.alloc(i32 3, i8* inttoptr (i32 3 to i8*))
|
||||
store i8* %pointerFree3, i8** @pointerFree3
|
||||
; Zero-sized object.
|
||||
%pointerFree0 = call ptr @runtime.alloc(i32 0, ptr inttoptr (i32 3 to ptr))
|
||||
store ptr %pointerFree0, ptr @pointerFree0
|
||||
%pointerFree0 = call i8* @runtime.alloc(i32 0, i8* inttoptr (i32 3 to i8*))
|
||||
store i8* %pointerFree0, i8** @pointerFree0
|
||||
|
||||
; Object made out of 3 pointers.
|
||||
%layout1 = call ptr @runtime.alloc(i32 12, ptr inttoptr (i32 67 to ptr))
|
||||
store ptr %layout1, ptr @layout1
|
||||
%layout1 = call i8* @runtime.alloc(i32 12, i8* inttoptr (i32 67 to i8*))
|
||||
store i8* %layout1, i8** @layout1
|
||||
; Array (or slice) of 5 slices.
|
||||
%layout2 = call ptr @runtime.alloc(i32 60, ptr inttoptr (i32 71 to ptr))
|
||||
store ptr %layout2, ptr @layout2
|
||||
%layout2 = call i8* @runtime.alloc(i32 60, i8* inttoptr (i32 71 to i8*))
|
||||
store i8* %layout2, i8** @layout2
|
||||
; Oddly shaped object, using all bits in the layout integer.
|
||||
%layout3 = call ptr @runtime.alloc(i32 104, ptr inttoptr (i32 2467830261 to ptr))
|
||||
store ptr %layout3, ptr @layout3
|
||||
%layout3 = call i8* @runtime.alloc(i32 104, i8* inttoptr (i32 2467830261 to i8*))
|
||||
store i8* %layout3, i8** @layout3
|
||||
; ...repeated.
|
||||
%layout4 = call ptr @runtime.alloc(i32 312, ptr inttoptr (i32 2467830261 to ptr))
|
||||
store ptr %layout4, ptr @layout4
|
||||
%layout4 = call i8* @runtime.alloc(i32 312, i8* inttoptr (i32 2467830261 to i8*))
|
||||
store i8* %layout4, i8** @layout4
|
||||
|
||||
; Large object that needs to be stored in a separate global.
|
||||
%bigobj1 = call ptr @runtime.alloc(i32 248, ptr @"runtime/gc.layout:62-2000000000000001")
|
||||
store ptr %bigobj1, ptr @bigobj1
|
||||
%bigobj1 = call i8* @runtime.alloc(i32 248, i8* bitcast ({ i32, [8 x i8] }* @"runtime/gc.layout:62-2000000000000001" to i8*))
|
||||
store i8* %bigobj1, i8** @bigobj1
|
||||
ret void
|
||||
}
|
||||
|
||||
Vendored
+14
-14
@@ -1,24 +1,24 @@
|
||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||
target triple = "wasm32--wasi"
|
||||
|
||||
@pointerFree12 = local_unnamed_addr global ptr @"main$alloc"
|
||||
@pointerFree7 = local_unnamed_addr global ptr @"main$alloc.1"
|
||||
@pointerFree3 = local_unnamed_addr global ptr @"main$alloc.2"
|
||||
@pointerFree0 = local_unnamed_addr global ptr @"main$alloc.3"
|
||||
@layout1 = local_unnamed_addr global ptr @"main$alloc.4"
|
||||
@layout2 = local_unnamed_addr global ptr @"main$alloc.5"
|
||||
@layout3 = local_unnamed_addr global ptr @"main$alloc.6"
|
||||
@layout4 = local_unnamed_addr global ptr @"main$alloc.7"
|
||||
@bigobj1 = local_unnamed_addr global ptr @"main$alloc.8"
|
||||
@pointerFree12 = local_unnamed_addr global i8* getelementptr inbounds ([12 x i8], [12 x i8]* @"main$alloc", i32 0, i32 0)
|
||||
@pointerFree7 = local_unnamed_addr global i8* getelementptr inbounds ([7 x i8], [7 x i8]* @"main$alloc.1", i32 0, i32 0)
|
||||
@pointerFree3 = local_unnamed_addr global i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"main$alloc.2", i32 0, i32 0)
|
||||
@pointerFree0 = local_unnamed_addr global i8* getelementptr inbounds ([0 x i8], [0 x i8]* @"main$alloc.3", i32 0, i32 0)
|
||||
@layout1 = local_unnamed_addr global i8* bitcast ([3 x i8*]* @"main$alloc.4" to i8*)
|
||||
@layout2 = local_unnamed_addr global i8* bitcast ([5 x { i8*, i32, i32 }]* @"main$alloc.5" to i8*)
|
||||
@layout3 = local_unnamed_addr global i8* bitcast ({ i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* }* @"main$alloc.6" to i8*)
|
||||
@layout4 = local_unnamed_addr global i8* bitcast ([3 x { i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* }]* @"main$alloc.7" to i8*)
|
||||
@bigobj1 = local_unnamed_addr global i8* bitcast ({ i8*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i8* }* @"main$alloc.8" to i8*)
|
||||
@"main$alloc" = internal global [12 x i8] zeroinitializer, align 4
|
||||
@"main$alloc.1" = internal global [7 x i8] zeroinitializer, align 4
|
||||
@"main$alloc.2" = internal global [3 x i8] zeroinitializer, align 4
|
||||
@"main$alloc.3" = internal global [0 x i8] zeroinitializer, align 4
|
||||
@"main$alloc.4" = internal global [3 x ptr] zeroinitializer, align 4
|
||||
@"main$alloc.5" = internal global [5 x { ptr, i32, i32 }] zeroinitializer, align 4
|
||||
@"main$alloc.6" = internal global { ptr, ptr, ptr, i32, i32, ptr, ptr, i32, i32, i32, i32, i32, i32, ptr, ptr, i32, i32, i32, ptr, ptr, i32, i32, ptr, i32, i32, ptr } zeroinitializer, align 4
|
||||
@"main$alloc.7" = internal global [3 x { ptr, ptr, ptr, i32, i32, ptr, ptr, i32, i32, i32, i32, i32, i32, ptr, ptr, i32, i32, i32, ptr, ptr, i32, i32, ptr, i32, i32, ptr }] zeroinitializer, align 4
|
||||
@"main$alloc.8" = internal global { ptr, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, ptr } zeroinitializer, align 4
|
||||
@"main$alloc.4" = internal global [3 x i8*] zeroinitializer, align 4
|
||||
@"main$alloc.5" = internal global [5 x { i8*, i32, i32 }] zeroinitializer, align 4
|
||||
@"main$alloc.6" = internal global { i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* } zeroinitializer, align 4
|
||||
@"main$alloc.7" = internal global [3 x { i8*, i8*, i8*, i32, i32, i8*, i8*, i32, i32, i32, i32, i32, i32, i8*, i8*, i32, i32, i32, i8*, i8*, i32, i32, i8*, i32, i32, i8* }] zeroinitializer, align 4
|
||||
@"main$alloc.8" = internal global { i8*, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i8* } zeroinitializer, align 4
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
ret void
|
||||
|
||||
Vendored
+21
-21
@@ -5,7 +5,7 @@ target triple = "x86_64--linux"
|
||||
@main.nonConst1 = global [4 x i64] zeroinitializer
|
||||
@main.nonConst2 = global i64 0
|
||||
@main.someArray = global [8 x {i16, i32}] zeroinitializer
|
||||
@main.exportedValue = global [1 x ptr] [ptr @main.exposedValue1]
|
||||
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
||||
@main.exportedConst = constant i64 42
|
||||
@main.exposedValue1 = global i16 0
|
||||
@main.exposedValue2 = global i16 0
|
||||
@@ -24,7 +24,7 @@ entry:
|
||||
|
||||
define void @main() unnamed_addr {
|
||||
entry:
|
||||
%0 = load i64, ptr @main.v1
|
||||
%0 = load i64, i64* @main.v1
|
||||
call void @runtime.printint64(i64 %0)
|
||||
call void @runtime.printnl()
|
||||
ret void
|
||||
@@ -37,43 +37,43 @@ entry:
|
||||
|
||||
define internal void @main.init() unnamed_addr {
|
||||
entry:
|
||||
store i64 3, ptr @main.v1
|
||||
store i64 3, i64* @main.v1
|
||||
call void @"main.init#1"()
|
||||
|
||||
; test the following pattern:
|
||||
; func someValue() int // extern function
|
||||
; var nonConst1 = [4]int{someValue(), 0, 0, 0}
|
||||
%value1 = call i64 @someValue()
|
||||
%gep1 = getelementptr [4 x i64], ptr @main.nonConst1, i32 0, i32 0
|
||||
store i64 %value1, ptr %gep1
|
||||
%gep1 = getelementptr [4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0
|
||||
store i64 %value1, i64* %gep1
|
||||
|
||||
; Test that the global really is marked dirty:
|
||||
; var nonConst2 = nonConst1[0]
|
||||
%gep2 = getelementptr [4 x i64], ptr @main.nonConst1, i32 0, i32 0
|
||||
%value2 = load i64, ptr %gep2
|
||||
store i64 %value2, ptr @main.nonConst2
|
||||
%gep2 = getelementptr [4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0
|
||||
%value2 = load i64, i64* %gep2
|
||||
store i64 %value2, i64* @main.nonConst2
|
||||
|
||||
; Test that the following GEP works:
|
||||
; var someArray
|
||||
; modifyExternal(&someArray[3].field1)
|
||||
%gep3 = getelementptr [8 x {i16, i32}], ptr @main.someArray, i32 0, i32 3, i32 1
|
||||
call void @modifyExternal(ptr %gep3)
|
||||
%gep3 = getelementptr [8 x {i16, i32}], [8 x {i16, i32}]* @main.someArray, i32 0, i32 3, i32 1
|
||||
call void @modifyExternal(i32* %gep3)
|
||||
|
||||
; Test that marking a value as external also marks all referenced values.
|
||||
call void @modifyExternal(ptr @main.exportedValue)
|
||||
store i16 5, ptr @main.exposedValue1
|
||||
call void @modifyExternal(i32* bitcast ([1 x i16*]* @main.exportedValue to i32*))
|
||||
store i16 5, i16* @main.exposedValue1
|
||||
|
||||
; Test that marking a constant as external still allows loading from it.
|
||||
call void @readExternal(ptr @main.exportedConst)
|
||||
%constLoad = load i64, ptr @main.exportedConst
|
||||
call void @readExternal(i32* bitcast (i64* @main.exportedConst to i32*))
|
||||
%constLoad = load i64, i64 * @main.exportedConst
|
||||
call void @runtime.printint64(i64 %constLoad)
|
||||
|
||||
; Test that this even propagates through functions.
|
||||
call void @modifyExternal(ptr @willModifyGlobal)
|
||||
store i16 7, ptr @main.exposedValue2
|
||||
call void @modifyExternal(i32* bitcast (void ()* @willModifyGlobal to i32*))
|
||||
store i16 7, i16* @main.exposedValue2
|
||||
|
||||
; Test that inline assembly is ignored.
|
||||
call void @modifyExternal(ptr @hasInlineAsm)
|
||||
call void @modifyExternal(i32* bitcast (void ()* @hasInlineAsm to i32*))
|
||||
|
||||
; Test switch statement.
|
||||
%switch1 = call i64 @testSwitch(i64 1) ; 1 returns 6
|
||||
@@ -86,7 +86,7 @@ entry:
|
||||
%elt = extractvalue {i8, i32, {float, {i64, i16}}} %agg, 2, 1, 0
|
||||
call void @runtime.printint64(i64 %elt)
|
||||
%agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
|
||||
store {i8, i32, {float, {i64, i16}}} %agg2, ptr @main.insertedValue
|
||||
store {i8, i32, {float, {i64, i16}}} %agg2, {i8, i32, {float, {i64, i16}}}* @main.insertedValue
|
||||
|
||||
ret void
|
||||
}
|
||||
@@ -100,16 +100,16 @@ entry:
|
||||
|
||||
declare i64 @someValue()
|
||||
|
||||
declare void @modifyExternal(ptr)
|
||||
declare void @modifyExternal(i32*)
|
||||
|
||||
declare void @readExternal(ptr)
|
||||
declare void @readExternal(i32*)
|
||||
|
||||
; This function will modify an external value. By passing this function as a
|
||||
; function pointer to an external function, @main.exposedValue2 should be
|
||||
; marked as external.
|
||||
define void @willModifyGlobal() {
|
||||
entry:
|
||||
store i16 8, ptr @main.exposedValue2
|
||||
store i16 8, i16* @main.exposedValue2
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
Vendored
+15
-15
@@ -4,7 +4,7 @@ target triple = "x86_64--linux"
|
||||
@main.nonConst1 = local_unnamed_addr global [4 x i64] zeroinitializer
|
||||
@main.nonConst2 = local_unnamed_addr global i64 0
|
||||
@main.someArray = global [8 x { i16, i32 }] zeroinitializer
|
||||
@main.exportedValue = global [1 x ptr] [ptr @main.exposedValue1]
|
||||
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
||||
@main.exportedConst = constant i64 42
|
||||
@main.exposedValue1 = global i16 0
|
||||
@main.exposedValue2 = local_unnamed_addr global i16 0
|
||||
@@ -19,17 +19,17 @@ entry:
|
||||
call void @runtime.printint64(i64 5)
|
||||
call void @runtime.printnl()
|
||||
%value1 = call i64 @someValue()
|
||||
store i64 %value1, ptr @main.nonConst1, align 8
|
||||
%value2 = load i64, ptr @main.nonConst1, align 8
|
||||
store i64 %value2, ptr @main.nonConst2, align 8
|
||||
call void @modifyExternal(ptr getelementptr inbounds (i8, ptr @main.someArray, i32 28))
|
||||
call void @modifyExternal(ptr @main.exportedValue)
|
||||
store i16 5, ptr @main.exposedValue1, align 2
|
||||
call void @readExternal(ptr @main.exportedConst)
|
||||
store i64 %value1, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0), align 8
|
||||
%value2 = load i64, i64* getelementptr inbounds ([4 x i64], [4 x i64]* @main.nonConst1, i32 0, i32 0), align 8
|
||||
store i64 %value2, i64* @main.nonConst2, align 8
|
||||
call void @modifyExternal(i32* bitcast (i8* getelementptr inbounds (i8, i8* bitcast ([8 x { i16, i32 }]* @main.someArray to i8*), i32 28) to i32*))
|
||||
call void @modifyExternal(i32* bitcast ([1 x i16*]* @main.exportedValue to i32*))
|
||||
store i16 5, i16* @main.exposedValue1, align 2
|
||||
call void @readExternal(i32* bitcast (i64* @main.exportedConst to i32*))
|
||||
call void @runtime.printint64(i64 42)
|
||||
call void @modifyExternal(ptr @willModifyGlobal)
|
||||
store i16 7, ptr @main.exposedValue2, align 2
|
||||
call void @modifyExternal(ptr @hasInlineAsm)
|
||||
call void @modifyExternal(i32* bitcast (void ()* @willModifyGlobal to i32*))
|
||||
store i16 7, i16* @main.exposedValue2, align 2
|
||||
call void @modifyExternal(i32* bitcast (void ()* @hasInlineAsm to i32*))
|
||||
call void @runtime.printint64(i64 6)
|
||||
call void @runtime.printint64(i64 -1)
|
||||
%agg = call { i8, i32, { float, { i64, i16 } } } @nestedStruct()
|
||||
@@ -42,7 +42,7 @@ entry:
|
||||
%agg2.insertvalue2 = insertvalue { i64, i16 } %agg2.agg1, i64 5, 0
|
||||
%agg2.insertvalue1 = insertvalue { float, { i64, i16 } } %agg2.agg0, { i64, i16 } %agg2.insertvalue2, 1
|
||||
%agg2.insertvalue0 = insertvalue { i8, i32, { float, { i64, i16 } } } %agg, { float, { i64, i16 } } %agg2.insertvalue1, 2
|
||||
store { i8, i32, { float, { i64, i16 } } } %agg2.insertvalue0, ptr @main.insertedValue, align 8
|
||||
store { i8, i32, { float, { i64, i16 } } } %agg2.insertvalue0, { i8, i32, { float, { i64, i16 } } }* @main.insertedValue, align 8
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -55,13 +55,13 @@ entry:
|
||||
|
||||
declare i64 @someValue() local_unnamed_addr
|
||||
|
||||
declare void @modifyExternal(ptr) local_unnamed_addr
|
||||
declare void @modifyExternal(i32*) local_unnamed_addr
|
||||
|
||||
declare void @readExternal(ptr) local_unnamed_addr
|
||||
declare void @readExternal(i32*) local_unnamed_addr
|
||||
|
||||
define void @willModifyGlobal() {
|
||||
entry:
|
||||
store i16 8, ptr @main.exposedValue2, align 2
|
||||
store i16 8, i16* @main.exposedValue2, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
Vendored
+11
-19
@@ -4,9 +4,8 @@ target triple = "x86_64--linux"
|
||||
@intToPtrResult = global i8 0
|
||||
@ptrToIntResult = global i8 0
|
||||
@icmpResult = global i8 0
|
||||
@pointerTagResult = global i64 0
|
||||
@someArray = internal global {i16, i8, i8} zeroinitializer
|
||||
@someArrayPointer = global ptr zeroinitializer
|
||||
@someArrayPointer = global i8* zeroinitializer
|
||||
|
||||
define void @runtime.initAll() {
|
||||
call void @main.init()
|
||||
@@ -18,56 +17,49 @@ define internal void @main.init() {
|
||||
call void @testPtrToInt()
|
||||
call void @testConstGEP()
|
||||
call void @testICmp()
|
||||
call void @testPointerTag()
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @testIntToPtr() {
|
||||
%nil = icmp eq ptr inttoptr (i64 1024 to ptr), null
|
||||
%nil = icmp eq i8* inttoptr (i64 1024 to i8*), null
|
||||
br i1 %nil, label %a, label %b
|
||||
a:
|
||||
; should not be reached
|
||||
store i8 1, ptr @intToPtrResult
|
||||
store i8 1, i8* @intToPtrResult
|
||||
ret void
|
||||
b:
|
||||
; should be reached
|
||||
store i8 2, ptr @intToPtrResult
|
||||
store i8 2, i8* @intToPtrResult
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @testPtrToInt() {
|
||||
%zero = icmp eq i64 ptrtoint (ptr @ptrToIntResult to i64), 0
|
||||
%zero = icmp eq i64 ptrtoint (i8* @ptrToIntResult to i64), 0
|
||||
br i1 %zero, label %a, label %b
|
||||
a:
|
||||
; should not be reached
|
||||
store i8 1, ptr @ptrToIntResult
|
||||
store i8 1, i8* @ptrToIntResult
|
||||
ret void
|
||||
b:
|
||||
; should be reached
|
||||
store i8 2, ptr @ptrToIntResult
|
||||
store i8 2, i8* @ptrToIntResult
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @testConstGEP() {
|
||||
store ptr getelementptr inbounds (i8, ptr @someArray, i32 2), ptr @someArrayPointer
|
||||
store i8* getelementptr inbounds (i8, i8* bitcast ({i16, i8, i8}* @someArray to i8*), i32 2), i8** @someArrayPointer
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @testICmp() {
|
||||
br i1 icmp eq (i64 ptrtoint (ptr @ptrToIntResult to i64), i64 0), label %equal, label %unequal
|
||||
br i1 icmp eq (i64 ptrtoint (i8* @ptrToIntResult to i64), i64 0), label %equal, label %unequal
|
||||
equal:
|
||||
; should not be reached
|
||||
store i8 1, ptr @icmpResult
|
||||
store i8 1, i8* @icmpResult
|
||||
ret void
|
||||
unequal:
|
||||
; should be reached
|
||||
store i8 2, ptr @icmpResult
|
||||
store i8 2, i8* @icmpResult
|
||||
ret void
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @testPointerTag() {
|
||||
%val = and i64 ptrtoint (ptr getelementptr inbounds (i8, ptr @someArray, i32 2) to i64), 3
|
||||
store i64 %val, ptr @pointerTagResult
|
||||
ret void
|
||||
}
|
||||
|
||||
Vendored
+1
-2
@@ -4,9 +4,8 @@ target triple = "x86_64--linux"
|
||||
@intToPtrResult = local_unnamed_addr global i8 2
|
||||
@ptrToIntResult = local_unnamed_addr global i8 2
|
||||
@icmpResult = local_unnamed_addr global i8 2
|
||||
@pointerTagResult = local_unnamed_addr global i64 2
|
||||
@someArray = internal global { i16, i8, i8 } zeroinitializer
|
||||
@someArrayPointer = local_unnamed_addr global ptr getelementptr inbounds ({ i16, i8, i8 }, ptr @someArray, i64 0, i32 1)
|
||||
@someArrayPointer = local_unnamed_addr global i8* getelementptr inbounds ({ i16, i8, i8 }, { i16, i8, i8 }* @someArray, i64 0, i32 1)
|
||||
|
||||
define void @runtime.initAll() local_unnamed_addr {
|
||||
ret void
|
||||
|
||||
Vendored
+9
-9
@@ -3,14 +3,14 @@ target triple = "x86_64--linux"
|
||||
|
||||
@main.v1 = global i1 0
|
||||
@main.v2 = global i1 0
|
||||
@"reflect/types.type:named:main.foo" = private constant { i8, ptr, ptr } { i8 34, ptr @"reflect/types.type:pointer:named:main.foo", ptr @"reflect/types.type:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:named:main.foo" = external constant { i8, ptr }
|
||||
@"reflect/types.type:named:main.foo" = private constant { i8, i8*, i8* } { i8 34, i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:pointer:named:main.foo", i32 0, i32 0), i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:basic:int", i32 0, i32 0) }, align 4
|
||||
@"reflect/types.type:pointer:named:main.foo" = external constant { i8, i8* }
|
||||
@"reflect/types.typeid:named:main.foo" = external constant i8
|
||||
@"reflect/types.type:basic:int" = private constant { i8, ptr } { i8 2, ptr @"reflect/types.type:pointer:basic:int" }, align 4
|
||||
@"reflect/types.type:pointer:basic:int" = external constant { i8, ptr }
|
||||
@"reflect/types.type:basic:int" = private constant { i8, i8* } { i8 2, i8* getelementptr inbounds ({ i8, i8* }, { i8, i8* }* @"reflect/types.type:pointer:basic:int", i32 0, i32 0) }, align 4
|
||||
@"reflect/types.type:pointer:basic:int" = external constant { i8, i8* }
|
||||
|
||||
|
||||
declare i1 @runtime.typeAssert(ptr, ptr, ptr, ptr)
|
||||
declare i1 @runtime.typeAssert(i8*, i8*, i8*, i8*)
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
entry:
|
||||
@@ -21,9 +21,9 @@ entry:
|
||||
define internal void @main.init() unnamed_addr {
|
||||
entry:
|
||||
; Test type asserts.
|
||||
%typecode = call i1 @runtime.typeAssert(ptr @"reflect/types.type:named:main.foo", ptr @"reflect/types.typeid:named:main.foo", ptr undef, ptr null)
|
||||
store i1 %typecode, ptr @main.v1
|
||||
%typecode2 = call i1 @runtime.typeAssert(ptr null, ptr @"reflect/types.typeid:named:main.foo", ptr undef, ptr null)
|
||||
store i1 %typecode2, ptr @main.v2
|
||||
%typecode = call i1 @runtime.typeAssert(i8* getelementptr inbounds ({ i8, i8*, i8* }, { i8, i8*, i8* }* @"reflect/types.type:named:main.foo", i32 0, i32 0), i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
|
||||
store i1 %typecode, i1* @main.v1
|
||||
%typecode2 = call i1 @runtime.typeAssert(i8* null, i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
|
||||
store i1 %typecode2, i1* @main.v2
|
||||
ret void
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -25,7 +25,7 @@ for.loop:
|
||||
br i1 %icmp, label %for.done, label %for.loop
|
||||
|
||||
for.done:
|
||||
store i8 %a, ptr @main.phiNodesResultA
|
||||
store i8 %b, ptr @main.phiNodesResultB
|
||||
store i8 %a, i8* @main.phiNodesResultA
|
||||
store i8 %b, i8* @main.phiNodesResultB
|
||||
ret void
|
||||
}
|
||||
|
||||
Vendored
+37
-34
@@ -3,7 +3,7 @@ target triple = "x86_64--linux"
|
||||
|
||||
declare void @externalCall(i64)
|
||||
|
||||
declare i64 @ptrHash(ptr nocapture)
|
||||
declare i64 @ptrHash(i8* nocapture)
|
||||
|
||||
@foo.knownAtRuntime = global i64 0
|
||||
@bar.knownAtRuntime = global i64 0
|
||||
@@ -17,60 +17,60 @@ declare i64 @ptrHash(ptr nocapture)
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
entry:
|
||||
call void @baz.init(ptr undef)
|
||||
call void @foo.init(ptr undef)
|
||||
call void @bar.init(ptr undef)
|
||||
call void @main.init(ptr undef)
|
||||
call void @x.init(ptr undef)
|
||||
call void @y.init(ptr undef)
|
||||
call void @z.init(ptr undef)
|
||||
call void @baz.init(i8* undef)
|
||||
call void @foo.init(i8* undef)
|
||||
call void @bar.init(i8* undef)
|
||||
call void @main.init(i8* undef)
|
||||
call void @x.init(i8* undef)
|
||||
call void @y.init(i8* undef)
|
||||
call void @z.init(i8* undef)
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @foo.init(ptr %context) unnamed_addr {
|
||||
store i64 5, ptr @foo.knownAtRuntime
|
||||
define internal void @foo.init(i8* %context) unnamed_addr {
|
||||
store i64 5, i64* @foo.knownAtRuntime
|
||||
unreachable ; this triggers a revert of @foo.init.
|
||||
}
|
||||
|
||||
define internal void @bar.init(ptr %context) unnamed_addr {
|
||||
%val = load i64, ptr @foo.knownAtRuntime
|
||||
store i64 %val, ptr @bar.knownAtRuntime
|
||||
define internal void @bar.init(i8* %context) unnamed_addr {
|
||||
%val = load i64, i64* @foo.knownAtRuntime
|
||||
store i64 %val, i64* @bar.knownAtRuntime
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @baz.init(ptr %context) unnamed_addr {
|
||||
define internal void @baz.init(i8* %context) unnamed_addr {
|
||||
; Test extractvalue/insertvalue with more than one index.
|
||||
%val = load [3 x {i64, i32}], ptr @baz.someGlobal
|
||||
%val = load [3 x {i64, i32}], [3 x {i64, i32}]* @baz.someGlobal
|
||||
%part = extractvalue [3 x {i64, i32}] %val, 0, 1
|
||||
%val2 = insertvalue [3 x {i64, i32}] %val, i32 5, 2, 1
|
||||
unreachable ; trigger revert
|
||||
}
|
||||
|
||||
define internal void @main.init(ptr %context) unnamed_addr {
|
||||
define internal void @main.init(i8* %context) unnamed_addr {
|
||||
entry:
|
||||
call void @externalCall(i64 3)
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
define internal void @x.init(ptr %context) unnamed_addr {
|
||||
define internal void @x.init(i8* %context) unnamed_addr {
|
||||
; Test atomic and volatile memory accesses.
|
||||
store atomic i32 1, ptr @x.atomicNum seq_cst, align 4
|
||||
%x = load atomic i32, ptr @x.atomicNum seq_cst, align 4
|
||||
store i32 %x, ptr @x.atomicNum
|
||||
%y = load volatile i32, ptr @x.volatileNum
|
||||
store volatile i32 %y, ptr @x.volatileNum
|
||||
store atomic i32 1, i32* @x.atomicNum seq_cst, align 4
|
||||
%x = load atomic i32, i32* @x.atomicNum seq_cst, align 4
|
||||
store i32 %x, i32* @x.atomicNum
|
||||
%y = load volatile i32, i32* @x.volatileNum
|
||||
store volatile i32 %y, i32* @x.volatileNum
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @y.init(ptr %context) unnamed_addr {
|
||||
define internal void @y.init(i8* %context) unnamed_addr {
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
; Test a wait-loop.
|
||||
; This function must be reverted.
|
||||
%val = load atomic i32, ptr @y.ready seq_cst, align 4
|
||||
%val = load atomic i32, i32* @y.ready seq_cst, align 4
|
||||
%ready = icmp eq i32 %val, 1
|
||||
br i1 %ready, label %end, label %loop
|
||||
|
||||
@@ -78,25 +78,27 @@ end:
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @z.init(ptr %context) unnamed_addr {
|
||||
define internal void @z.init(i8* %context) unnamed_addr {
|
||||
%bloom = bitcast i64* @z.bloom to i8*
|
||||
|
||||
; This can be safely expanded.
|
||||
call void @z.setArr(ptr @z.bloom, i64 1, ptr @z.bloom)
|
||||
call void @z.setArr(i8* %bloom, i64 1, i8* %bloom)
|
||||
|
||||
; This call should be reverted to prevent unrolling.
|
||||
call void @z.setArr(ptr @z.arr, i64 32, ptr @z.bloom)
|
||||
call void @z.setArr(i8* bitcast ([32 x i8]* @z.arr to i8*), i64 32, i8* %bloom)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @z.setArr(ptr %arr, i64 %n, ptr %context) unnamed_addr {
|
||||
define internal void @z.setArr(i8* %arr, i64 %n, i8* %context) unnamed_addr {
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%prev = phi i64 [ %n, %entry ], [ %idx, %loop ]
|
||||
%idx = sub i64 %prev, 1
|
||||
%elem = getelementptr i8, ptr %arr, i64 %idx
|
||||
call void @z.set(ptr %elem, ptr %context)
|
||||
%elem = getelementptr i8, i8* %arr, i64 %idx
|
||||
call void @z.set(i8* %elem, i8* %context)
|
||||
%done = icmp eq i64 %idx, 0
|
||||
br i1 %done, label %end, label %loop
|
||||
|
||||
@@ -104,13 +106,14 @@ end:
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @z.set(ptr %ptr, ptr %context) unnamed_addr {
|
||||
define internal void @z.set(i8* %ptr, i8* %context) unnamed_addr {
|
||||
; Insert the pointer into the Bloom filter.
|
||||
%hash = call i64 @ptrHash(ptr %ptr)
|
||||
%hash = call i64 @ptrHash(i8* %ptr)
|
||||
%index = lshr i64 %hash, 58
|
||||
%bit = shl i64 1, %index
|
||||
%old = load i64, ptr %context
|
||||
%bloom = bitcast i8* %context to i64*
|
||||
%old = load i64, i64* %bloom
|
||||
%new = or i64 %old, %bit
|
||||
store i64 %new, ptr %context
|
||||
store i64 %new, i64* %bloom
|
||||
ret void
|
||||
}
|
||||
|
||||
Vendored
+28
-27
@@ -13,41 +13,41 @@ target triple = "x86_64--linux"
|
||||
|
||||
declare void @externalCall(i64) local_unnamed_addr
|
||||
|
||||
declare i64 @ptrHash(ptr nocapture) local_unnamed_addr
|
||||
declare i64 @ptrHash(i8* nocapture) local_unnamed_addr
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
entry:
|
||||
call fastcc void @baz.init(ptr undef)
|
||||
call fastcc void @foo.init(ptr undef)
|
||||
%val = load i64, ptr @foo.knownAtRuntime, align 8
|
||||
store i64 %val, ptr @bar.knownAtRuntime, align 8
|
||||
call fastcc void @baz.init(i8* undef)
|
||||
call fastcc void @foo.init(i8* undef)
|
||||
%val = load i64, i64* @foo.knownAtRuntime, align 8
|
||||
store i64 %val, i64* @bar.knownAtRuntime, align 8
|
||||
call void @externalCall(i64 3)
|
||||
store atomic i32 1, ptr @x.atomicNum seq_cst, align 4
|
||||
%x = load atomic i32, ptr @x.atomicNum seq_cst, align 4
|
||||
store i32 %x, ptr @x.atomicNum, align 4
|
||||
%y = load volatile i32, ptr @x.volatileNum, align 4
|
||||
store volatile i32 %y, ptr @x.volatileNum, align 4
|
||||
call fastcc void @y.init(ptr undef)
|
||||
call fastcc void @z.set(ptr @z.bloom, ptr @z.bloom)
|
||||
call fastcc void @z.setArr(ptr @z.arr, i64 32, ptr @z.bloom)
|
||||
store atomic i32 1, i32* @x.atomicNum seq_cst, align 4
|
||||
%x = load atomic i32, i32* @x.atomicNum seq_cst, align 4
|
||||
store i32 %x, i32* @x.atomicNum, align 4
|
||||
%y = load volatile i32, i32* @x.volatileNum, align 4
|
||||
store volatile i32 %y, i32* @x.volatileNum, align 4
|
||||
call fastcc void @y.init(i8* undef)
|
||||
call fastcc void @z.set(i8* bitcast (i64* @z.bloom to i8*), i8* bitcast (i64* @z.bloom to i8*))
|
||||
call fastcc void @z.setArr(i8* getelementptr inbounds ([32 x i8], [32 x i8]* @z.arr, i32 0, i32 0), i64 32, i8* bitcast (i64* @z.bloom to i8*))
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal fastcc void @foo.init(ptr %context) unnamed_addr {
|
||||
store i64 5, ptr @foo.knownAtRuntime, align 8
|
||||
define internal fastcc void @foo.init(i8* %context) unnamed_addr {
|
||||
store i64 5, i64* @foo.knownAtRuntime, align 8
|
||||
unreachable
|
||||
}
|
||||
|
||||
define internal fastcc void @baz.init(ptr %context) unnamed_addr {
|
||||
define internal fastcc void @baz.init(i8* %context) unnamed_addr {
|
||||
unreachable
|
||||
}
|
||||
|
||||
define internal fastcc void @y.init(ptr %context) unnamed_addr {
|
||||
define internal fastcc void @y.init(i8* %context) unnamed_addr {
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
loop: ; preds = %loop, %entry
|
||||
%val = load atomic i32, ptr @y.ready seq_cst, align 4
|
||||
%val = load atomic i32, i32* @y.ready seq_cst, align 4
|
||||
%ready = icmp eq i32 %val, 1
|
||||
br i1 %ready, label %end, label %loop
|
||||
|
||||
@@ -55,15 +55,15 @@ end: ; preds = %loop
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal fastcc void @z.setArr(ptr %arr, i64 %n, ptr %context) unnamed_addr {
|
||||
define internal fastcc void @z.setArr(i8* %arr, i64 %n, i8* %context) unnamed_addr {
|
||||
entry:
|
||||
br label %loop
|
||||
|
||||
|
||||
loop: ; preds = %loop, %entry
|
||||
%prev = phi i64 [ %n, %entry ], [ %idx, %loop ]
|
||||
%idx = sub i64 %prev, 1
|
||||
%elem = getelementptr i8, ptr %arr, i64 %idx
|
||||
call fastcc void @z.set(ptr %elem, ptr %context)
|
||||
%elem = getelementptr i8, i8* %arr, i64 %idx
|
||||
call fastcc void @z.set(i8* %elem, i8* %context)
|
||||
%done = icmp eq i64 %idx, 0
|
||||
br i1 %done, label %end, label %loop
|
||||
|
||||
@@ -71,12 +71,13 @@ end: ; preds = %loop
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal fastcc void @z.set(ptr %ptr, ptr %context) unnamed_addr {
|
||||
%hash = call i64 @ptrHash(ptr %ptr)
|
||||
define internal fastcc void @z.set(i8* %ptr, i8* %context) unnamed_addr {
|
||||
%hash = call i64 @ptrHash(i8* %ptr)
|
||||
%index = lshr i64 %hash, 58
|
||||
%bit = shl i64 1, %index
|
||||
%old = load i64, ptr %context, align 8
|
||||
%bloom = bitcast i8* %context to i64*
|
||||
%old = load i64, i64* %bloom, align 8
|
||||
%new = or i64 %old, %bit
|
||||
store i64 %new, ptr %context, align 8
|
||||
store i64 %new, i64* %bloom, align 8
|
||||
ret void
|
||||
}
|
||||
}
|
||||
Vendored
+35
-32
@@ -2,15 +2,15 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64--linux"
|
||||
|
||||
@main.uint8SliceSrc.buf = internal global [2 x i8] c"\03d"
|
||||
@main.uint8SliceSrc = internal unnamed_addr global { ptr, i64, i64 } { ptr @main.uint8SliceSrc.buf, i64 2, i64 2 }
|
||||
@main.uint8SliceDst = internal unnamed_addr global { ptr, i64, i64 } zeroinitializer
|
||||
@main.uint8SliceSrc = internal unnamed_addr global { i8*, i64, i64 } { i8* getelementptr inbounds ([2 x i8], [2 x i8]* @main.uint8SliceSrc.buf, i32 0, i32 0), i64 2, i64 2 }
|
||||
@main.uint8SliceDst = internal unnamed_addr global { i8*, i64, i64 } zeroinitializer
|
||||
@main.int16SliceSrc.buf = internal global [3 x i16] [i16 5, i16 123, i16 1024]
|
||||
@main.int16SliceSrc = internal unnamed_addr global { ptr, i64, i64 } { ptr @main.int16SliceSrc.buf, i64 3, i64 3 }
|
||||
@main.int16SliceDst = internal unnamed_addr global { ptr, i64, i64 } zeroinitializer
|
||||
@main.int16SliceSrc = internal unnamed_addr global { i16*, i64, i64 } { i16* getelementptr inbounds ([3 x i16], [3 x i16]* @main.int16SliceSrc.buf, i32 0, i32 0), i64 3, i64 3 }
|
||||
@main.int16SliceDst = internal unnamed_addr global { i16*, i64, i64 } zeroinitializer
|
||||
|
||||
declare i64 @runtime.sliceCopy(ptr %dst, ptr %src, i64 %dstLen, i64 %srcLen, i64 %elemSize) unnamed_addr
|
||||
declare i64 @runtime.sliceCopy(i8* %dst, i8* %src, i64 %dstLen, i64 %srcLen, i64 %elemSize) unnamed_addr
|
||||
|
||||
declare ptr @runtime.alloc(i64, ptr) unnamed_addr
|
||||
declare i8* @runtime.alloc(i64, i8*) unnamed_addr
|
||||
|
||||
declare void @runtime.printuint8(i8)
|
||||
|
||||
@@ -25,23 +25,23 @@ entry:
|
||||
define void @main() unnamed_addr {
|
||||
entry:
|
||||
; print(uintSliceSrc[0])
|
||||
%uint8SliceSrc.buf = load ptr, ptr @main.uint8SliceSrc
|
||||
%uint8SliceSrc.val = load i8, ptr %uint8SliceSrc.buf
|
||||
%uint8SliceSrc.buf = load i8*, i8** getelementptr inbounds ({ i8*, i64, i64 }, { i8*, i64, i64 }* @main.uint8SliceSrc, i64 0, i32 0)
|
||||
%uint8SliceSrc.val = load i8, i8* %uint8SliceSrc.buf
|
||||
call void @runtime.printuint8(i8 %uint8SliceSrc.val)
|
||||
|
||||
; print(uintSliceDst[0])
|
||||
%uint8SliceDst.buf = load ptr, ptr @main.uint8SliceDst
|
||||
%uint8SliceDst.val = load i8, ptr %uint8SliceDst.buf
|
||||
%uint8SliceDst.buf = load i8*, i8** getelementptr inbounds ({ i8*, i64, i64 }, { i8*, i64, i64 }* @main.uint8SliceDst, i64 0, i32 0)
|
||||
%uint8SliceDst.val = load i8, i8* %uint8SliceDst.buf
|
||||
call void @runtime.printuint8(i8 %uint8SliceDst.val)
|
||||
|
||||
; print(int16SliceSrc[0])
|
||||
%int16SliceSrc.buf = load ptr, ptr @main.int16SliceSrc
|
||||
%int16SliceSrc.val = load i16, ptr %int16SliceSrc.buf
|
||||
%int16SliceSrc.buf = load i16*, i16** getelementptr inbounds ({ i16*, i64, i64 }, { i16*, i64, i64 }* @main.int16SliceSrc, i64 0, i32 0)
|
||||
%int16SliceSrc.val = load i16, i16* %int16SliceSrc.buf
|
||||
call void @runtime.printint16(i16 %int16SliceSrc.val)
|
||||
|
||||
; print(int16SliceDst[0])
|
||||
%int16SliceDst.buf = load ptr, ptr @main.int16SliceDst
|
||||
%int16SliceDst.val = load i16, ptr %int16SliceDst.buf
|
||||
%int16SliceDst.buf = load i16*, i16** getelementptr inbounds ({ i16*, i64, i64 }, { i16*, i64, i64 }* @main.int16SliceDst, i64 0, i32 0)
|
||||
%int16SliceDst.val = load i16, i16* %int16SliceDst.buf
|
||||
call void @runtime.printint16(i16 %int16SliceDst.val)
|
||||
ret void
|
||||
}
|
||||
@@ -50,34 +50,37 @@ define internal void @main.init() unnamed_addr {
|
||||
entry:
|
||||
; equivalent of:
|
||||
; uint8SliceDst = make([]uint8, len(uint8SliceSrc))
|
||||
%uint8SliceSrc = load { ptr, i64, i64 }, ptr @main.uint8SliceSrc
|
||||
%uint8SliceSrc.len = extractvalue { ptr, i64, i64 } %uint8SliceSrc, 1
|
||||
%uint8SliceDst.buf = call ptr @runtime.alloc(i64 %uint8SliceSrc.len, ptr null)
|
||||
%0 = insertvalue { ptr, i64, i64 } undef, ptr %uint8SliceDst.buf, 0
|
||||
%1 = insertvalue { ptr, i64, i64 } %0, i64 %uint8SliceSrc.len, 1
|
||||
%2 = insertvalue { ptr, i64, i64 } %1, i64 %uint8SliceSrc.len, 2
|
||||
store { ptr, i64, i64 } %2, ptr @main.uint8SliceDst
|
||||
%uint8SliceSrc = load { i8*, i64, i64 }, { i8*, i64, i64 }* @main.uint8SliceSrc
|
||||
%uint8SliceSrc.len = extractvalue { i8*, i64, i64 } %uint8SliceSrc, 1
|
||||
%uint8SliceDst.buf = call i8* @runtime.alloc(i64 %uint8SliceSrc.len, i8* null)
|
||||
%0 = insertvalue { i8*, i64, i64 } undef, i8* %uint8SliceDst.buf, 0
|
||||
%1 = insertvalue { i8*, i64, i64 } %0, i64 %uint8SliceSrc.len, 1
|
||||
%2 = insertvalue { i8*, i64, i64 } %1, i64 %uint8SliceSrc.len, 2
|
||||
store { i8*, i64, i64 } %2, { i8*, i64, i64 }* @main.uint8SliceDst
|
||||
|
||||
; equivalent of:
|
||||
; copy(uint8SliceDst, uint8SliceSrc)
|
||||
%uint8SliceSrc.buf = extractvalue { ptr, i64, i64 } %uint8SliceSrc, 0
|
||||
%copy.n = call i64 @runtime.sliceCopy(ptr %uint8SliceDst.buf, ptr %uint8SliceSrc.buf, i64 %uint8SliceSrc.len, i64 %uint8SliceSrc.len, i64 1)
|
||||
%uint8SliceSrc.buf = extractvalue { i8*, i64, i64 } %uint8SliceSrc, 0
|
||||
%copy.n = call i64 @runtime.sliceCopy(i8* %uint8SliceDst.buf, i8* %uint8SliceSrc.buf, i64 %uint8SliceSrc.len, i64 %uint8SliceSrc.len, i64 1)
|
||||
|
||||
; equivalent of:
|
||||
; int16SliceDst = make([]int16, len(int16SliceSrc))
|
||||
%int16SliceSrc = load { ptr, i64, i64 }, ptr @main.int16SliceSrc
|
||||
%int16SliceSrc.len = extractvalue { ptr, i64, i64 } %int16SliceSrc, 1
|
||||
%int16SliceSrc = load { i16*, i64, i64 }, { i16*, i64, i64 }* @main.int16SliceSrc
|
||||
%int16SliceSrc.len = extractvalue { i16*, i64, i64 } %int16SliceSrc, 1
|
||||
%int16SliceSrc.len.bytes = mul i64 %int16SliceSrc.len, 2
|
||||
%int16SliceDst.buf = call ptr @runtime.alloc(i64 %int16SliceSrc.len.bytes, ptr null)
|
||||
%3 = insertvalue { ptr, i64, i64 } undef, ptr %int16SliceDst.buf, 0
|
||||
%4 = insertvalue { ptr, i64, i64 } %3, i64 %int16SliceSrc.len, 1
|
||||
%5 = insertvalue { ptr, i64, i64 } %4, i64 %int16SliceSrc.len, 2
|
||||
store { ptr, i64, i64 } %5, ptr @main.int16SliceDst
|
||||
%int16SliceDst.buf.raw = call i8* @runtime.alloc(i64 %int16SliceSrc.len.bytes, i8* null)
|
||||
%int16SliceDst.buf = bitcast i8* %int16SliceDst.buf.raw to i16*
|
||||
%3 = insertvalue { i16*, i64, i64 } undef, i16* %int16SliceDst.buf, 0
|
||||
%4 = insertvalue { i16*, i64, i64 } %3, i64 %int16SliceSrc.len, 1
|
||||
%5 = insertvalue { i16*, i64, i64 } %4, i64 %int16SliceSrc.len, 2
|
||||
store { i16*, i64, i64 } %5, { i16*, i64, i64 }* @main.int16SliceDst
|
||||
|
||||
; equivalent of:
|
||||
; copy(int16SliceDst, int16SliceSrc)
|
||||
%int16SliceSrc.buf = extractvalue { ptr, i64, i64 } %int16SliceSrc, 0
|
||||
%copy.n2 = call i64 @runtime.sliceCopy(ptr %int16SliceDst.buf, ptr %int16SliceSrc.buf, i64 %int16SliceSrc.len, i64 %int16SliceSrc.len, i64 2)
|
||||
%int16SliceSrc.buf = extractvalue { i16*, i64, i64 } %int16SliceSrc, 0
|
||||
%int16SliceSrc.buf.i8ptr = bitcast i16* %int16SliceSrc.buf to i8*
|
||||
%int16SliceDst.buf.i8ptr = bitcast i16* %int16SliceDst.buf to i8*
|
||||
%copy.n2 = call i64 @runtime.sliceCopy(i8* %int16SliceDst.buf.i8ptr, i8* %int16SliceSrc.buf.i8ptr, i64 %int16SliceSrc.len, i64 %int16SliceSrc.len, i64 2)
|
||||
|
||||
ret void
|
||||
}
|
||||
|
||||
Submodule lib/renesas-svd deleted from 03d7688085
@@ -207,11 +207,6 @@ func listGorootMergeLinks(goroot, tinygoroot string, overrides map[string]bool)
|
||||
merges[dir] = filepath.Join(goroot, dir)
|
||||
}
|
||||
|
||||
// Required starting in Go 1.21 due to https://github.com/golang/go/issues/61928
|
||||
if _, err := os.Stat(filepath.Join(goroot, "go.env")); err == nil {
|
||||
merges["go.env"] = filepath.Join(goroot, "go.env")
|
||||
}
|
||||
|
||||
return merges, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"regexp"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -237,9 +236,6 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
if testConfig.RunRegexp != "" {
|
||||
flags = append(flags, "-test.run="+testConfig.RunRegexp)
|
||||
}
|
||||
if testConfig.SkipRegexp != "" {
|
||||
flags = append(flags, "-test.skip="+testConfig.SkipRegexp)
|
||||
}
|
||||
if testConfig.BenchRegexp != "" {
|
||||
flags = append(flags, "-test.bench="+testConfig.BenchRegexp)
|
||||
}
|
||||
@@ -252,9 +248,6 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
if testConfig.Count != nil && *testConfig.Count != 1 {
|
||||
flags = append(flags, "-test.count="+strconv.Itoa(*testConfig.Count))
|
||||
}
|
||||
if testConfig.Shuffle != "" {
|
||||
flags = append(flags, "-test.shuffle="+testConfig.Shuffle)
|
||||
}
|
||||
|
||||
logToStdout := testConfig.Verbose || testConfig.BenchRegexp != ""
|
||||
|
||||
@@ -349,7 +342,7 @@ func Test(pkgName string, stdout, stderr io.Writer, options *compileopts.Options
|
||||
fmt.Fprintf(w, "? \t%s\t[no test files]\n", err.ImportPath)
|
||||
// Pretend the test passed - it at least didn't fail.
|
||||
return true, nil
|
||||
} else if passed && !testConfig.CompileOnly {
|
||||
} else if passed {
|
||||
fmt.Fprintf(w, "ok \t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
} else {
|
||||
fmt.Fprintf(w, "FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
|
||||
@@ -533,7 +526,7 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
return fmt.Errorf("unknown flash method: %s", flashMethod)
|
||||
}
|
||||
if options.Monitor {
|
||||
return Monitor(result.Executable, "", options)
|
||||
return Monitor("", options)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -946,131 +939,104 @@ func touchSerialPortAt1200bps(port string) (err error) {
|
||||
return fmt.Errorf("opening port: %s", err)
|
||||
}
|
||||
|
||||
func flashUF2UsingMSD(volumes []string, tmppath string, options *compileopts.Options) error {
|
||||
for start := time.Now(); time.Since(start) < options.Timeout; {
|
||||
// Find a UF2 mount point.
|
||||
mounts, err := findFATMounts(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, mount := range mounts {
|
||||
for _, volume := range volumes {
|
||||
if mount.name != volume {
|
||||
continue
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(mount.path, "INFO_UF2.TXT")); err != nil {
|
||||
// No INFO_UF2.TXT found, which is expected on a UF2
|
||||
// filesystem.
|
||||
continue
|
||||
}
|
||||
// Found the filesystem, so flash the device!
|
||||
return moveFile(tmppath, filepath.Join(mount.path, "flash.uf2"))
|
||||
}
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
return errors.New("unable to locate any volume: [" + strings.Join(volumes, ",") + "]")
|
||||
}
|
||||
|
||||
func flashHexUsingMSD(volumes []string, tmppath string, options *compileopts.Options) error {
|
||||
for start := time.Now(); time.Since(start) < options.Timeout; {
|
||||
// Find all mount points.
|
||||
mounts, err := findFATMounts(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, mount := range mounts {
|
||||
for _, volume := range volumes {
|
||||
if mount.name != volume {
|
||||
continue
|
||||
}
|
||||
// Found the filesystem, so flash the device!
|
||||
return moveFile(tmppath, filepath.Join(mount.path, "flash.hex"))
|
||||
}
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
return errors.New("unable to locate any volume: [" + strings.Join(volumes, ",") + "]")
|
||||
}
|
||||
|
||||
type mountPoint struct {
|
||||
name string
|
||||
path string
|
||||
}
|
||||
|
||||
// Find all the mount points on the system that use the FAT filesystem.
|
||||
func findFATMounts(options *compileopts.Options) ([]mountPoint, error) {
|
||||
var points []mountPoint
|
||||
func flashUF2UsingMSD(volume, tmppath string, options *compileopts.Options) error {
|
||||
// find standard UF2 info path
|
||||
var infoPath string
|
||||
switch runtime.GOOS {
|
||||
case "linux", "freebsd":
|
||||
fi, err := os.Stat("/run/media")
|
||||
if err != nil || !fi.IsDir() {
|
||||
infoPath = "/media/*/" + volume + "/INFO_UF2.TXT"
|
||||
} else {
|
||||
infoPath = "/run/media/*/" + volume + "/INFO_UF2.TXT"
|
||||
}
|
||||
case "darwin":
|
||||
list, err := os.ReadDir("/Volumes")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not list mount points: %w", err)
|
||||
}
|
||||
for _, elem := range list {
|
||||
// TODO: find a way to check for the filesystem type.
|
||||
// (Only return FAT filesystems).
|
||||
points = append(points, mountPoint{
|
||||
name: elem.Name(),
|
||||
path: filepath.Join("/Volumes", elem.Name()),
|
||||
})
|
||||
}
|
||||
sort.Slice(points, func(i, j int) bool {
|
||||
return points[i].path < points[j].name
|
||||
})
|
||||
return points, nil
|
||||
case "linux":
|
||||
tab, err := os.ReadFile("/proc/mounts") // symlink to /proc/self/mounts on my system
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not list mount points: %w", err)
|
||||
}
|
||||
for _, line := range strings.Split(string(tab), "\n") {
|
||||
fields := strings.Fields(line)
|
||||
if len(fields) <= 2 {
|
||||
continue
|
||||
}
|
||||
fstype := fields[2]
|
||||
if fstype != "vfat" {
|
||||
continue
|
||||
}
|
||||
points = append(points, mountPoint{
|
||||
name: filepath.Base(fields[1]),
|
||||
path: fields[1],
|
||||
})
|
||||
}
|
||||
return points, nil
|
||||
infoPath = "/Volumes/" + volume + "/INFO_UF2.TXT"
|
||||
case "windows":
|
||||
// Obtain a list of all currently mounted volumes.
|
||||
cmd := executeCommand(options, "wmic",
|
||||
"PATH", "Win32_LogicalDisk",
|
||||
"get", "DeviceID,VolumeName,FileSystem,DriveType")
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
err := cmd.Run()
|
||||
path, err := windowsFindUSBDrive(volume, options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not list mount points: %w", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Extract data to convert to a []mountPoint slice.
|
||||
for _, line := range strings.Split(out.String(), "\n") {
|
||||
words := strings.Fields(line)
|
||||
if len(words) < 3 {
|
||||
continue
|
||||
}
|
||||
if words[1] != "2" || words[2] != "FAT" {
|
||||
// - DriveType 2 is removable (which we're looking for).
|
||||
// - We only want to return FAT filesystems.
|
||||
continue
|
||||
}
|
||||
points = append(points, mountPoint{
|
||||
name: words[3],
|
||||
path: words[0],
|
||||
})
|
||||
}
|
||||
return points, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown GOOS for listing mount points: %s", runtime.GOOS)
|
||||
infoPath = path + "/INFO_UF2.TXT"
|
||||
}
|
||||
|
||||
d, err := locateDevice(volume, infoPath, options.Timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return moveFile(tmppath, filepath.Dir(d)+"/flash.uf2")
|
||||
}
|
||||
|
||||
func flashHexUsingMSD(volume, tmppath string, options *compileopts.Options) error {
|
||||
// find expected volume path
|
||||
var destPath string
|
||||
switch runtime.GOOS {
|
||||
case "linux", "freebsd":
|
||||
fi, err := os.Stat("/run/media")
|
||||
if err != nil || !fi.IsDir() {
|
||||
destPath = "/media/*/" + volume
|
||||
} else {
|
||||
destPath = "/run/media/*/" + volume
|
||||
}
|
||||
case "darwin":
|
||||
destPath = "/Volumes/" + volume
|
||||
case "windows":
|
||||
path, err := windowsFindUSBDrive(volume, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destPath = path + "/"
|
||||
}
|
||||
|
||||
d, err := locateDevice(volume, destPath, options.Timeout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return moveFile(tmppath, d+"/flash.hex")
|
||||
}
|
||||
|
||||
func locateDevice(volume, path string, timeout time.Duration) (string, error) {
|
||||
var d []string
|
||||
var err error
|
||||
for start := time.Now(); time.Since(start) < timeout; {
|
||||
d, err = filepath.Glob(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if d != nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
if d == nil {
|
||||
return "", errors.New("unable to locate device: " + volume)
|
||||
}
|
||||
return d[0], nil
|
||||
}
|
||||
|
||||
func windowsFindUSBDrive(volume string, options *compileopts.Options) (string, error) {
|
||||
cmd := executeCommand(options, "wmic",
|
||||
"PATH", "Win32_LogicalDisk", "WHERE", "VolumeName = '"+volume+"'",
|
||||
"get", "DeviceID,VolumeName,FileSystem,DriveType")
|
||||
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, line := range strings.Split(out.String(), "\n") {
|
||||
words := strings.Fields(line)
|
||||
if len(words) >= 3 {
|
||||
if words[1] == "2" && words[2] == "FAT" {
|
||||
return words[0], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", errors.New("unable to locate a USB device to be flashed")
|
||||
}
|
||||
|
||||
// getDefaultPort returns the default serial port depending on the operating system.
|
||||
@@ -1420,6 +1386,9 @@ func main() {
|
||||
serial := flag.String("serial", "", "which serial output to use (none, uart, usb)")
|
||||
work := flag.Bool("work", false, "print the name of the temporary build directory and do not delete this directory on exit")
|
||||
interpTimeout := flag.Duration("interp-timeout", 180*time.Second, "interp optimization pass timeout")
|
||||
printIR := flag.Bool("printir", false, "print LLVM IR")
|
||||
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
|
||||
verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR")
|
||||
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")
|
||||
@@ -1446,17 +1415,6 @@ func main() {
|
||||
monitor := flag.Bool("monitor", false, "enable serial monitor")
|
||||
baudrate := flag.Int("baudrate", 115200, "baudrate of serial monitor")
|
||||
|
||||
// Internal flags, that are only intended for TinyGo development.
|
||||
printIR := flag.Bool("internal-printir", false, "print LLVM IR")
|
||||
dumpSSA := flag.Bool("internal-dumpssa", false, "dump internal Go SSA")
|
||||
verifyIR := flag.Bool("internal-verifyir", false, "run extra verification steps on LLVM IR")
|
||||
// Don't generate debug information in the IR, to make IR more readable.
|
||||
// You generally want debug information in IR for various features, like
|
||||
// stack size calculation and features like -size=short, -print-allocs=,
|
||||
// etc. The -no-debug flag is used to strip it at link time. But for TinyGo
|
||||
// development it can be useful to not emit debug information at all.
|
||||
skipDwarf := flag.Bool("internal-nodwarf", false, "internal flag, use -no-debug instead")
|
||||
|
||||
var flagJSON, flagDeps, flagTest bool
|
||||
if command == "help" || command == "list" || command == "info" || command == "build" {
|
||||
flag.BoolVar(&flagJSON, "json", false, "print data in JSON format")
|
||||
@@ -1476,12 +1434,10 @@ func main() {
|
||||
flag.BoolVar(&testConfig.Verbose, "v", false, "verbose: print additional output")
|
||||
flag.BoolVar(&testConfig.Short, "short", false, "short: run smaller test suite to save time")
|
||||
flag.StringVar(&testConfig.RunRegexp, "run", "", "run: regexp of tests to run")
|
||||
flag.StringVar(&testConfig.SkipRegexp, "skip", "", "skip: regexp of tests to skip")
|
||||
testConfig.Count = flag.Int("count", 1, "count: number of times to run tests/benchmarks `count` times")
|
||||
flag.StringVar(&testConfig.BenchRegexp, "bench", "", "bench: regexp of benchmarks to run")
|
||||
flag.StringVar(&testConfig.BenchRegexp, "bench", "", "run: regexp of benchmarks to run")
|
||||
flag.StringVar(&testConfig.BenchTime, "benchtime", "", "run each benchmark for duration `d`")
|
||||
flag.BoolVar(&testConfig.BenchMem, "benchmem", false, "show memory stats for benchmarks")
|
||||
flag.StringVar(&testConfig.Shuffle, "shuffle", "", "shuffle the order the tests and benchmarks run")
|
||||
}
|
||||
|
||||
// Early command processing, before commands are interpreted by the Go flag
|
||||
@@ -1533,7 +1489,6 @@ func main() {
|
||||
PrintIR: *printIR,
|
||||
DumpSSA: *dumpSSA,
|
||||
VerifyIR: *verifyIR,
|
||||
SkipDWARF: *skipDwarf,
|
||||
Semaphore: make(chan struct{}, *parallelism),
|
||||
Debug: !*nodebug,
|
||||
PrintSizes: *printSize,
|
||||
@@ -1575,6 +1530,15 @@ func main() {
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
|
||||
// Limit the number of threads to one.
|
||||
// This is an attempted workaround for the crashes we're seeing in CI on
|
||||
// Windows. If this change helps, it indicates there is a concurrency issue.
|
||||
// If it doesn't, then there is something else going on. Either way, this
|
||||
// should be removed once the test is done.
|
||||
if runtime.GOOS == "windows" {
|
||||
runtime.GOMAXPROCS(1)
|
||||
}
|
||||
|
||||
switch command {
|
||||
case "build":
|
||||
pkgName := "."
|
||||
@@ -1739,7 +1703,7 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
case "monitor":
|
||||
err := Monitor("", *port, options)
|
||||
err := Monitor(*port, options)
|
||||
handleCompilerError(err)
|
||||
case "targets":
|
||||
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
|
||||
@@ -1796,17 +1760,15 @@ func main() {
|
||||
}
|
||||
if flagJSON {
|
||||
json, _ := json.MarshalIndent(struct {
|
||||
Target *compileopts.TargetSpec `json:"target"`
|
||||
GOROOT string `json:"goroot"`
|
||||
GOOS string `json:"goos"`
|
||||
GOARCH string `json:"goarch"`
|
||||
GOARM string `json:"goarm"`
|
||||
BuildTags []string `json:"build_tags"`
|
||||
GC string `json:"garbage_collector"`
|
||||
Scheduler string `json:"scheduler"`
|
||||
LLVMTriple string `json:"llvm_triple"`
|
||||
GOROOT string `json:"goroot"`
|
||||
GOOS string `json:"goos"`
|
||||
GOARCH string `json:"goarch"`
|
||||
GOARM string `json:"goarm"`
|
||||
BuildTags []string `json:"build_tags"`
|
||||
GC string `json:"garbage_collector"`
|
||||
Scheduler string `json:"scheduler"`
|
||||
LLVMTriple string `json:"llvm_triple"`
|
||||
}{
|
||||
Target: config.Target,
|
||||
GOROOT: cachedGOROOT,
|
||||
GOOS: config.GOOS(),
|
||||
GOARCH: config.GOARCH(),
|
||||
@@ -1873,7 +1835,7 @@ func main() {
|
||||
usage(command)
|
||||
case "version":
|
||||
goversion := "<unknown>"
|
||||
if s, err := goenv.GorootVersionString(); err == nil {
|
||||
if s, err := goenv.GorootVersionString(goenv.Get("GOROOT")); err == nil {
|
||||
goversion = s
|
||||
}
|
||||
version := goenv.Version
|
||||
|
||||
+2
-24
@@ -34,16 +34,6 @@ var supportedLinuxArches = map[string]string{
|
||||
"X86Linux": "linux/386",
|
||||
"ARMLinux": "linux/arm/6",
|
||||
"ARM64Linux": "linux/arm64",
|
||||
"WASIp1": "wasip1/wasm",
|
||||
}
|
||||
|
||||
func init() {
|
||||
major, _, _ := goenv.GetGorootVersion()
|
||||
if major < 21 {
|
||||
// Go 1.20 backwards compatibility.
|
||||
// Should be removed once we drop support for Go 1.20.
|
||||
delete(supportedLinuxArches, "WASIp1")
|
||||
}
|
||||
}
|
||||
|
||||
var sema = make(chan struct{}, runtime.NumCPU())
|
||||
@@ -81,16 +71,6 @@ func TestBuild(t *testing.T) {
|
||||
"zeroalloc.go",
|
||||
}
|
||||
|
||||
// Go 1.21 made some changes to the language, which we can only test when
|
||||
// we're actually on Go 1.21.
|
||||
_, minor, err := goenv.GetGorootVersion()
|
||||
if err != nil {
|
||||
t.Fatal("could not get version:", minor)
|
||||
}
|
||||
if minor >= 21 {
|
||||
tests = append(tests, "go1.21.go")
|
||||
}
|
||||
|
||||
if *testTarget != "" {
|
||||
// This makes it possible to run one specific test (instead of all),
|
||||
// which is especially useful to quickly check whether some changes
|
||||
@@ -186,8 +166,6 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
t.Fatal("failed to load target spec:", err)
|
||||
}
|
||||
|
||||
isWebAssembly := options.Target == "wasi" || options.Target == "wasm" || (options.Target == "" && options.GOARCH == "wasm")
|
||||
|
||||
for _, name := range tests {
|
||||
if options.GOOS == "linux" && (options.GOARCH == "arm" || options.GOARCH == "386") {
|
||||
switch name {
|
||||
@@ -238,7 +216,7 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
runTest("env.go", options, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
|
||||
})
|
||||
}
|
||||
if isWebAssembly {
|
||||
if options.Target == "wasi" || options.Target == "wasm" {
|
||||
t.Run("alias.go-scheduler-none", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
options := compileopts.Options(options)
|
||||
@@ -258,7 +236,7 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
runTest("rand.go", options, t, nil, nil)
|
||||
})
|
||||
}
|
||||
if !isWebAssembly {
|
||||
if options.Target != "wasi" && options.Target != "wasm" {
|
||||
// The recover() builtin isn't supported yet on WebAssembly and Windows.
|
||||
t.Run("recover.go", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
+5
-134
@@ -1,18 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"debug/dwarf"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/token"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/mattn/go-tty"
|
||||
@@ -22,7 +13,7 @@ import (
|
||||
)
|
||||
|
||||
// Monitor connects to the given port and reads/writes the serial port.
|
||||
func Monitor(executable, port string, options *compileopts.Options) error {
|
||||
func Monitor(port string, options *compileopts.Options) error {
|
||||
config, err := builder.NewConfig(options)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -83,31 +74,17 @@ func Monitor(executable, port string, options *compileopts.Options) error {
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, 100*1024)
|
||||
var line []byte
|
||||
for {
|
||||
n, err := p.Read(buf)
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("read error: %w", err)
|
||||
return
|
||||
}
|
||||
start := 0
|
||||
for i, c := range buf[:n] {
|
||||
if c == '\n' {
|
||||
os.Stdout.Write(buf[start : i+1])
|
||||
start = i + 1
|
||||
address := extractPanicAddress(line)
|
||||
if address != 0 {
|
||||
loc, err := addressToLine(executable, address)
|
||||
if err == nil && loc.IsValid() {
|
||||
fmt.Printf("[tinygo: panic at %s]\n", loc.String())
|
||||
}
|
||||
}
|
||||
line = line[:0]
|
||||
} else {
|
||||
line = append(line, c)
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
continue
|
||||
}
|
||||
os.Stdout.Write(buf[start:n])
|
||||
fmt.Printf("%v", string(buf[:n]))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -127,109 +104,3 @@ func Monitor(executable, port string, options *compileopts.Options) error {
|
||||
|
||||
return <-errCh
|
||||
}
|
||||
|
||||
var addressMatch = regexp.MustCompile(`^panic: runtime error at 0x([0-9a-f]+): `)
|
||||
|
||||
// Extract the address from the "panic: runtime error at" message.
|
||||
func extractPanicAddress(line []byte) uint64 {
|
||||
matches := addressMatch.FindSubmatch(line)
|
||||
if matches != nil {
|
||||
address, err := strconv.ParseUint(string(matches[1]), 16, 64)
|
||||
if err == nil {
|
||||
return address
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Convert an address in the binary to a source address location.
|
||||
func addressToLine(executable string, address uint64) (token.Position, error) {
|
||||
data, err := readDWARF(executable)
|
||||
if err != nil {
|
||||
return token.Position{}, err
|
||||
}
|
||||
r := data.Reader()
|
||||
|
||||
for {
|
||||
e, err := r.Next()
|
||||
if err != nil {
|
||||
return token.Position{}, err
|
||||
}
|
||||
if e == nil {
|
||||
break
|
||||
}
|
||||
switch e.Tag {
|
||||
case dwarf.TagCompileUnit:
|
||||
r.SkipChildren()
|
||||
lr, err := data.LineReader(e)
|
||||
if err != nil {
|
||||
return token.Position{}, err
|
||||
}
|
||||
var lineEntry = dwarf.LineEntry{
|
||||
EndSequence: true,
|
||||
}
|
||||
for {
|
||||
// Read the next .debug_line entry.
|
||||
prevLineEntry := lineEntry
|
||||
err := lr.Next(&lineEntry)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return token.Position{}, err
|
||||
}
|
||||
|
||||
if prevLineEntry.EndSequence && lineEntry.Address == 0 {
|
||||
// Tombstone value. This symbol has been removed, for
|
||||
// example by the --gc-sections linker flag. It is still
|
||||
// here in the debug information because the linker can't
|
||||
// just remove this reference.
|
||||
// Read until the next EndSequence so that this sequence is
|
||||
// skipped.
|
||||
// For more details, see (among others):
|
||||
// https://reviews.llvm.org/D84825
|
||||
for {
|
||||
err := lr.Next(&lineEntry)
|
||||
if err != nil {
|
||||
return token.Position{}, err
|
||||
}
|
||||
if lineEntry.EndSequence {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !prevLineEntry.EndSequence {
|
||||
// The chunk describes the code from prevLineEntry to
|
||||
// lineEntry.
|
||||
if prevLineEntry.Address <= address && lineEntry.Address > address {
|
||||
return token.Position{
|
||||
Filename: prevLineEntry.File.Name,
|
||||
Line: prevLineEntry.Line,
|
||||
Column: prevLineEntry.Column,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return token.Position{}, nil // location not found
|
||||
}
|
||||
|
||||
// Read the DWARF debug information from a given file (in various formats).
|
||||
func readDWARF(executable string) (*dwarf.Data, error) {
|
||||
f, err := os.Open(executable)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if file, err := elf.NewFile(f); err == nil {
|
||||
return file.DWARF()
|
||||
} else if file, err := macho.NewFile(f); err == nil {
|
||||
return file.DWARF()
|
||||
} else if file, err := pe.NewFile(f); err == nil {
|
||||
return file.DWARF()
|
||||
} else {
|
||||
return nil, errors.New("unknown binary format")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/tinygo-org/tinygo/builder"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
)
|
||||
|
||||
func TestTraceback(t *testing.T) {
|
||||
if runtime.GOOS != "linux" {
|
||||
// We care about testing the ELF format, which is only used on Linux
|
||||
// (not on MacOS or Windows).
|
||||
t.Skip("Test only works on Linux")
|
||||
}
|
||||
|
||||
// Build a small binary that only panics.
|
||||
tmpdir := t.TempDir()
|
||||
config, err := builder.NewConfig(&compileopts.Options{
|
||||
GOOS: runtime.GOOS,
|
||||
GOARCH: runtime.GOARCH,
|
||||
Opt: "z",
|
||||
InterpTimeout: time.Minute,
|
||||
Debug: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result, err := builder.Build("testdata/trivialpanic.go", ".elf", tmpdir, config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Run this binary, and capture the output.
|
||||
buf := &bytes.Buffer{}
|
||||
cmd := exec.Command(result.Binary)
|
||||
cmd.Stdout = buf
|
||||
cmd.Stderr = buf
|
||||
cmd.Run() // this will return an error because of the panic, ignore it
|
||||
|
||||
// Extract the "runtime error at" address.
|
||||
line := bytes.TrimSpace(buf.Bytes())
|
||||
address := extractPanicAddress(line)
|
||||
if address == 0 {
|
||||
t.Fatalf("could not extract panic address from %#v", string(line))
|
||||
}
|
||||
|
||||
// Look up the source location for this address.
|
||||
location, err := addressToLine(result.Executable, address)
|
||||
if err != nil {
|
||||
t.Fatal("could not read source location:", err)
|
||||
}
|
||||
|
||||
// Verify that the source location is as expected.
|
||||
if filepath.Base(location.Filename) != "trivialpanic.go" {
|
||||
t.Errorf("expected path to end with trivialpanic.go, got %#v", location.Filename)
|
||||
}
|
||||
if location.Line != 6 {
|
||||
t.Errorf("expected panic location to be line 6, got line %d", location.Line)
|
||||
}
|
||||
}
|
||||
+21
-374
@@ -51,39 +51,20 @@ var (
|
||||
GRAPHICS = (*GRAPHICS_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x004C)))
|
||||
|
||||
// GBA Sound Channel 1 - Tone & Sweep
|
||||
SOUND1 = (*SOUND1_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0060)))
|
||||
SOUND1 = (*SOUND_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0060)))
|
||||
|
||||
// GBA Sound Channel 2 - Tone
|
||||
SOUND2 = (*SOUND2_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0068)))
|
||||
SOUND2 = (*SOUND_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0068)))
|
||||
|
||||
// GBA Sound Channel 3 - Wave Output
|
||||
SOUND3 = (*SOUND3_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0070)))
|
||||
|
||||
// GBA Sound Channel 4 - Noise
|
||||
SOUND4 = (*SOUND4_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0078)))
|
||||
|
||||
// GBA Sound Control
|
||||
SOUND = (*SOUND_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0080)))
|
||||
|
||||
DMA0 = (*DMA_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x00B0)))
|
||||
DMA1 = (*DMA_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x00BC)))
|
||||
DMA2 = (*DMA_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x00C8)))
|
||||
DMA3 = (*DMA_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x00D4)))
|
||||
// TODO: Sound channel 3 and 4
|
||||
|
||||
TM0 = (*TIMER_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0100)))
|
||||
TM1 = (*TIMER_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0104)))
|
||||
TM2 = (*TIMER_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0108)))
|
||||
TM3 = (*TIMER_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x010C)))
|
||||
|
||||
// Communication 1
|
||||
SIODATA32 = (*SIODATA32_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0120)))
|
||||
SIOMULTI = (*SIOMULTI_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0120)))
|
||||
|
||||
KEY = (*KEY_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0130)))
|
||||
|
||||
// Communication 2
|
||||
SIO = (*SIO_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0134)))
|
||||
|
||||
INTERRUPT = (*INTERRUPT_Type)(unsafe.Add(unsafe.Pointer(REG_BASE), uintptr(0x0200)))
|
||||
)
|
||||
|
||||
@@ -138,11 +119,8 @@ const (
|
||||
// Screenblock size
|
||||
SBB_SIZE = 0x00800
|
||||
|
||||
// BG VRAM_MODE_0_2 size
|
||||
VRAM_BG_SIZE_MODE_0_2 = 0x10000
|
||||
|
||||
// BG VRAM size
|
||||
VRAM_BG_SIZE_MODE_3_5 = 0x14000
|
||||
VRAM_BG_SIZE = 0x10000
|
||||
|
||||
// Object VRAM size
|
||||
VRAM_OBJ_SIZE = 0x08000
|
||||
@@ -176,11 +154,8 @@ var (
|
||||
// Back page address
|
||||
MEM_VRAM_BACK = MEM_VRAM + VRAM_PAGE_SIZE
|
||||
|
||||
// Object VRAM address - BG Mode 0-2
|
||||
MEM_VRAM_OBJ_MODE0_2 = MEM_VRAM + VRAM_BG_SIZE_MODE_0_2
|
||||
|
||||
// Object VRAM address - BG Mode 3-5
|
||||
MEM_VRAM_OBJ_MODE_3_5 = MEM_VRAM + VRAM_BG_SIZE_MODE_3_5
|
||||
// Object VRAM address
|
||||
MEM_VRAM_OBJ = MEM_VRAM + VRAM_BG_SIZE
|
||||
)
|
||||
|
||||
// Display registers
|
||||
@@ -246,7 +221,7 @@ type GRAPHICS_Type struct {
|
||||
BLDY volatile.Register16
|
||||
}
|
||||
|
||||
type SOUND1_Type struct {
|
||||
type SOUND_Type struct {
|
||||
// Sweep register
|
||||
CNT_L volatile.Register16
|
||||
|
||||
@@ -257,59 +232,7 @@ type SOUND1_Type struct {
|
||||
CNT_X volatile.Register16
|
||||
}
|
||||
|
||||
type SOUND2_Type struct {
|
||||
// Duty/Len/Envelope
|
||||
CNT_L volatile.Register16
|
||||
|
||||
// not used
|
||||
_ volatile.Register16
|
||||
|
||||
// Frequency/Control
|
||||
CNT_H volatile.Register16
|
||||
}
|
||||
|
||||
type SOUND3_Type struct {
|
||||
// Stop/Wave RAM select
|
||||
CNT_L volatile.Register16
|
||||
|
||||
// Length/Volume
|
||||
CNT_H volatile.Register16
|
||||
|
||||
// Frequency/Control
|
||||
CNT_X volatile.Register16
|
||||
}
|
||||
|
||||
type SOUND4_Type struct {
|
||||
// Length/Envelope
|
||||
CNT_L volatile.Register16
|
||||
|
||||
// not used
|
||||
_ volatile.Register16
|
||||
|
||||
// Frequency/Control
|
||||
CNT_H volatile.Register16
|
||||
}
|
||||
|
||||
type SOUND_Type struct {
|
||||
// Control Stereo/Volume/Enable
|
||||
CNT_L volatile.Register16
|
||||
|
||||
// Control Mixing/DMA Control
|
||||
CNT_H volatile.Register16
|
||||
|
||||
// Control Sound on/off
|
||||
CNT_X volatile.Register16
|
||||
}
|
||||
|
||||
// DMA
|
||||
type DMA_Type struct {
|
||||
SAD_L volatile.Register16
|
||||
SAD_H volatile.Register16
|
||||
DAD_L volatile.Register16
|
||||
DAD_H volatile.Register16
|
||||
CNT_L volatile.Register16
|
||||
CNT_H volatile.Register16
|
||||
}
|
||||
// TODO: DMA
|
||||
|
||||
// TIMER
|
||||
type TIMER_Type struct {
|
||||
@@ -317,28 +240,7 @@ type TIMER_Type struct {
|
||||
CNT volatile.Register16
|
||||
}
|
||||
|
||||
// serial
|
||||
type SIODATA32_Type struct {
|
||||
DATA32_L volatile.Register16
|
||||
DATA32_H volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
CNT volatile.Register16
|
||||
DATA8 volatile.Register16
|
||||
}
|
||||
|
||||
type SIOMULTI_Type struct {
|
||||
MULTI0 volatile.Register16
|
||||
MULTI1 volatile.Register16
|
||||
MULTI2 volatile.Register16
|
||||
MULTI3 volatile.Register16
|
||||
CNT volatile.Register16
|
||||
MLT_SEND volatile.Register16
|
||||
}
|
||||
|
||||
type SIO_Type struct {
|
||||
RCNT volatile.Register16
|
||||
}
|
||||
// TODO: serial
|
||||
|
||||
// Keypad registers
|
||||
type KEY_Type struct {
|
||||
@@ -357,34 +259,6 @@ type INTERRUPT_Type struct {
|
||||
PAUSE volatile.Register16
|
||||
}
|
||||
|
||||
// LCD OBJ Attributes
|
||||
type OAMOBJ_Type struct {
|
||||
ATT0 volatile.Register16
|
||||
ATT1 volatile.Register16
|
||||
ATT2 volatile.Register16
|
||||
_ volatile.Register16
|
||||
}
|
||||
|
||||
// OAM Rotation/Scaling Parameters
|
||||
type OAMROT_Type struct {
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
PA volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
PB volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
PC volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
_ volatile.Register16
|
||||
PD volatile.Register16
|
||||
}
|
||||
|
||||
// Constants for DISP: display
|
||||
const (
|
||||
// BGMODE: background mode.
|
||||
@@ -498,40 +372,6 @@ const (
|
||||
DISPSTAT_VCOUNT_SETTING_Pos = 0x8
|
||||
)
|
||||
|
||||
const (
|
||||
BGCNT_PRIORITY_Pos = 0x0
|
||||
BGCNT_PRIORITY_Msk = 0x3
|
||||
|
||||
BGCNT_CHAR_BASE_Pos = 0x2
|
||||
BGCNT_CHAR_BASE_Msk = 0x3
|
||||
|
||||
BGCNT_MOSAIC_Pos = 0x6
|
||||
BGCNT_MOSAIC_DISABLE = 0x0
|
||||
BGCNT_MOSAIC_ENABLE = 0x1
|
||||
|
||||
BGCNT_COLORS_Pos = 0x7
|
||||
BGCNT_COLORS_16 = 0x0
|
||||
BGCNT_COLORS_256 = 0x1
|
||||
|
||||
BGCNT_BASE_Pos = 0x8
|
||||
BGCNT_BASE_Msk = 0x1F
|
||||
|
||||
BGCNT_OVERFLOW_Pos = 0xD
|
||||
BGCNT_OVERFLOW_TRANS = 0x0
|
||||
BGCNT_OVERFLOW_WRAP = 0x1
|
||||
|
||||
BGCNT_SIZE_Pos = 0xE
|
||||
BGCNT_SIZE_Msk = 0x3
|
||||
)
|
||||
|
||||
const (
|
||||
BG_HOFS_Pos = 0x0
|
||||
BG_HOFS_Msk = 0x1FF
|
||||
|
||||
BG_VOFS_Pos = 0x0
|
||||
BG_VOFS_Msk = 0x1FF
|
||||
)
|
||||
|
||||
// Constants for TIMER
|
||||
const (
|
||||
// PRESCALER: Prescaler Selection (0=F/1, 1=F/64, 2=F/256, 3=F/1024)
|
||||
@@ -563,135 +403,6 @@ const (
|
||||
TIMERCNT_TIMER_STOP = 0x0
|
||||
)
|
||||
|
||||
const (
|
||||
// normal mode
|
||||
SIOCNT_NORMAL_SC_Pos = 0x0
|
||||
SIOCNT_NORMAL_SC_INTERNAL = 0x1
|
||||
SIOCNT_NORMAL_SC_EXTERNAL = 0x0
|
||||
|
||||
SIOCNT_NORMAL_SCSPEED_Pos = 0x1
|
||||
SIOCNT_NORMAL_SCSPEED_256K = 0x0
|
||||
SIOCNT_NORMAL_SCSPEED_2M = 0x1
|
||||
|
||||
SIOCNT_NORMAL_SCSTATE_Pos = 0x2
|
||||
SIOCNT_NORMAL_SCSTATE_LOW = 0x0
|
||||
SIOCNT_NORMAL_SCSTATE_HIGH = 0x1
|
||||
|
||||
SIOCNT_NORMAL_SO_INACTIVE_Pos = 0x3
|
||||
SIOCNT_NORMAL_SO_INACTIVE_LOW = 0x0
|
||||
SIOCNT_NORMAL_SO_INACTIVE_HIGH = 0x1
|
||||
|
||||
SIOCNT_NORMAL_START_Pos = 0x7
|
||||
SIOCNT_NORMAL_START_READY = 0x0
|
||||
SIOCNT_NORMAL_START_ACTIVE = 0x1
|
||||
|
||||
SIOCNT_NORMAL_LEN_Pos = 0xC
|
||||
SIOCNT_NORMAL_LEN8 = 0x0
|
||||
SIOCNT_NORMAL_LEN32 = 0x1
|
||||
|
||||
SIOCNT_NORMAL_MODE_Pos = 0xD
|
||||
SIOCNT_NORMAL_MODE = 0x0
|
||||
|
||||
// multiplayer mode
|
||||
SIOCNT_MULTI_BR_Pos = 0x0
|
||||
SIOCNT_MULTI_BR_Msk = 0x3
|
||||
SIOCNT_MULTI_BR_9600 = 0x0
|
||||
SIOCNT_MULTI_BR_38400 = 0x1
|
||||
SIOCNT_MULTI_BR_57600 = 0x2
|
||||
SIOCNT_MULTI_BR_115200 = 0x3
|
||||
|
||||
SIOCNT_MULTI_SI_Pos = 0x2
|
||||
SIOCNT_MULTI_SI_PARENT = 0x0
|
||||
SIOCNT_MULTI_SI_CHILD = 0x1
|
||||
|
||||
SIOCNT_MULTI_SD_Pos = 0x3
|
||||
SIOCNT_MULTI_SD_BAD = 0x0
|
||||
SIOCNT_MULTI_SD_READY = 0x1
|
||||
|
||||
SIOCNT_MULTI_ID_Pos = 0x4
|
||||
SIOCNT_MULTI_ID_Msk = 0x3
|
||||
SIOCNT_MULTI_ID_PARENT = 0x0
|
||||
SIOCNT_MULTI_ID_CHILD1 = 0x1
|
||||
SIOCNT_MULTI_ID_CHILD2 = 0x2
|
||||
SIOCNT_MULTI_ID_CHILD3 = 0x3
|
||||
|
||||
SIOCNT_MULTI_ERR_Pos = 0x6
|
||||
SIOCNT_MULTI_ERR_NORMAL = 0x0
|
||||
SIOCNT_MULTI_ERR_ERROR = 0x1
|
||||
|
||||
SIOCNT_MULTI_STARTBUSY_Pos = 0x7
|
||||
SIOCNT_MULTI_STARTBUSY_INACTIVE = 0x0
|
||||
SIOCNT_MULTI_STARTBUSY_STARTBUSY = 0x1
|
||||
|
||||
SIOCNT_MULTI_MODE_Pos = 0xC
|
||||
SIOCNT_MULTI_MODE_Msk = 0x3
|
||||
SIOCNT_MULTI_MODE = 0x01
|
||||
|
||||
// uart mode
|
||||
SIOCNT_UART_BR_Pos = 0x0
|
||||
SIOCNT_UART_BR_Msk = 0x3
|
||||
SIOCNT_UART_BR_9600 = 0x0
|
||||
SIOCNT_UART_BR_38400 = 0x1
|
||||
SIOCNT_UART_BR_57600 = 0x2
|
||||
SIOCNT_UART_BR_115200 = 0x3
|
||||
|
||||
SIOCNT_UART_CTS_Pos = 0x2
|
||||
SIOCNT_UART_CTS_ALWAYS = 0x0
|
||||
SIOCNT_UART_CTS_SENDLOW = 0x1
|
||||
|
||||
SIOCNT_UART_PARITY_Pos = 0x3
|
||||
SIOCNT_UART_PARITY_EVEN = 0x0
|
||||
SIOCNT_UART_PARITY_ODD = 0x1
|
||||
|
||||
SIOCNT_UART_SEND_Pos = 0x4
|
||||
SIOCNT_UART_SEND_NOTFULL = 0x0
|
||||
SIOCNT_UART_SEND_FULL = 0x1
|
||||
|
||||
SIOCNT_UART_REC_Pos = 0x5
|
||||
SIOCNT_UART_REC_NOTEMPTY = 0x0
|
||||
SIOCNT_UART_REC_EMPTY = 0x1
|
||||
|
||||
SIOCNT_UART_ERR_Pos = 0x6
|
||||
SIOCNT_UART_ERR_NOERROR = 0x0
|
||||
SIOCNT_UART_ERR_ERROR = 0x1
|
||||
|
||||
SIOCNT_UART_DATALEN_Pos = 0x7
|
||||
SIOCNT_UART_DATALEN_7 = 0x0
|
||||
SIOCNT_UART_DATALEN_8 = 0x1
|
||||
|
||||
SIOCNT_UART_FIFO_Pos = 0x8
|
||||
SIOCNT_UART_FIFO_DISABLE = 0x0
|
||||
SIOCNT_UART_FIFO_ENABLE = 0x1
|
||||
|
||||
SIOCNT_UART_PARITY_ENABLE_Pos = 0x9
|
||||
SIOCNT_UART_PARITY_DISABLE = 0x0
|
||||
SIOCNT_UART_PARITY_ENABLE = 0x1
|
||||
|
||||
SIOCNT_UART_SEND_ENABLE_Pos = 0xA
|
||||
SIOCNT_UART_SEND_DISABLE = 0x0
|
||||
SIOCNT_UART_SEND_ENABLE = 0x1
|
||||
|
||||
SIOCNT_UART_REC_ENABLE_Pos = 0xB
|
||||
SIOCNT_UART_REC_DISABLE = 0x0
|
||||
SIOCNT_UART_REC_ENABLE = 0x1
|
||||
|
||||
SIOCNT_UART_MODE_Pos = 0xC
|
||||
SIOCNT_UART_MODE_Msk = 0x3
|
||||
SIOCNT_UART_MODE = 0x11
|
||||
|
||||
// IRQs used by all
|
||||
SIOCNT_IRQ_Pos = 0xE
|
||||
SIOCNT_IRQ_DISABLE = 0x0
|
||||
SIOCNT_IRQ_ENABLE = 0x1
|
||||
)
|
||||
|
||||
const (
|
||||
SIO_RCNT_MODE_Pos = 0xF
|
||||
SIO_RCNT_MODE_NORMAL = 0x0
|
||||
SIO_RCNT_MODE_MULTI = 0x0
|
||||
SIO_RCNT_MODE_UART = 0x0
|
||||
)
|
||||
|
||||
// Constants for KEY
|
||||
const (
|
||||
// KEYINPUT
|
||||
@@ -709,24 +420,18 @@ const (
|
||||
KEYINPUT_BUTTON_L_Pos = 0x9
|
||||
|
||||
// KEYCNT
|
||||
KEYCNT_IGNORE = 0x0
|
||||
KEYCNT_SELECT = 0x1
|
||||
KEYCNT_BUTTON_A_Pos = 0x0
|
||||
KEYCNT_BUTTON_B_Pos = 0x1
|
||||
KEYCNT_BUTTON_SELECT_Pos = 0x2
|
||||
KEYCNT_BUTTON_START_Pos = 0x3
|
||||
KEYCNT_BUTTON_RIGHT_Pos = 0x4
|
||||
KEYCNT_BUTTON_LEFT_Pos = 0x5
|
||||
KEYCNT_BUTTON_UP_Pos = 0x6
|
||||
KEYCNT_BUTTON_DOWN_Pos = 0x7
|
||||
KEYCNT_BUTTON_R_Pos = 0x8
|
||||
KEYCNT_BUTTON_L_Pos = 0x9
|
||||
KEYCNT_BUTTON_IRQ_DISABLE = 0x0
|
||||
KEYCNT_BUTTON_IRQ_ENABLE = 0x1
|
||||
KEYCNT_BUTTON_IRQ_ENABLE_Pos = 0xE
|
||||
KEYCNT_BUTTON_IRQ_COND_OR = 0x0
|
||||
KEYCNT_BUTTON_IRQ_COND_AND = 0x1
|
||||
KEYCNT_BUTTON_IRQ_COND_Pos = 0xF
|
||||
KEYCNT_IGNORE = 0x0
|
||||
KEYCNT_SELECT = 0x1
|
||||
KEYCNT_BUTTON_A_Pos = 0x0
|
||||
KEYCNT_BUTTON_B_Pos = 0x1
|
||||
KEYCNT_BUTTON_SELECT_Pos = 0x2
|
||||
KEYCNT_BUTTON_START_Pos = 0x3
|
||||
KEYCNT_BUTTON_RIGHT_Pos = 0x4
|
||||
KEYCNT_BUTTON_LEFT_Pos = 0x5
|
||||
KEYCNT_BUTTON_UP_Pos = 0x6
|
||||
KEYCNT_BUTTON_DOWN_Pos = 0x7
|
||||
KEYCNT_BUTTON_R_Pos = 0x8
|
||||
KEYCNT_BUTTON_L_Pos = 0x9
|
||||
)
|
||||
|
||||
// Constants for INTERRUPT
|
||||
@@ -767,61 +472,3 @@ const (
|
||||
INTERRUPT_IF_KEYPAD_Pos = 0xC
|
||||
INTERRUPT_IF_GAMPAK_Pos = 0xD
|
||||
)
|
||||
|
||||
const (
|
||||
OAMOBJ_ATT0_Y_Pos = 0x0
|
||||
OAMOBJ_ATT0_Y_Msk = 0xFF
|
||||
|
||||
OAMOBJ_ATT0_OM_Pos = 0x8
|
||||
OAMOBJ_ATT0_OM_Msk = 0x3
|
||||
OAMOBJ_ATT0_OM_REG = 0x0
|
||||
OAMOBJ_ATT0_OM_AFF = 0x1
|
||||
OAMOBJ_ATT0_OM_HIDE = 0x2
|
||||
OAMOBJ_ATT0_OM_DBL = 0x3
|
||||
|
||||
OAMOBJ_ATT0_GM_Pos = 0xA
|
||||
OAMOBJ_ATT0_GM_Msk = 0x3
|
||||
OAMOBJ_ATT0_GM_REG = 0x0
|
||||
OAMOBJ_ATT0_GM_BLEND = 0x1
|
||||
OAMOBJ_ATT0_GM_WIN = 0x2
|
||||
|
||||
OAMOBJ_ATT0_MOSAIC_Pos = 0xC
|
||||
OAMOBJ_ATT0_MOSAIC_DISABLE = 0x0
|
||||
OAMOBJ_ATT0_MOSAIC_ENABLE = 0x1
|
||||
|
||||
OAMOBJ_ATT0_COLOR_Pos = 0xD
|
||||
OAMOBJ_ATT0_COLOR_4BPP = 0x0
|
||||
OAMOBJ_ATT0_COLOR_8BPP = 0x1
|
||||
|
||||
OAMOBJ_ATT0_SH_Pos = 0xE
|
||||
OAMOBJ_ATT0_SH_Msk = 0x3
|
||||
OAMOBJ_ATT0_SH_SQUARE = 0x0
|
||||
OAMOBJ_ATT0_SH_WIDE = 0x1
|
||||
OAMOBJ_ATT0_SH_TALL = 0x2
|
||||
|
||||
OAMOBJ_ATT1_X_Pos = 0x0
|
||||
OAMOBJ_ATT1_X_Msk = 0xFF
|
||||
|
||||
OAMOBJ_ATT1_AID_Pos = 0x9
|
||||
OAMOBJ_ATT1_AID_Msk = 0x1F
|
||||
|
||||
OAMOBJ_ATT1_HF_Pos = 0xC
|
||||
OAMOBJ_ATT1_HF_NOFLIP = 0x0
|
||||
OAMOBJ_ATT1_HF_FLIP = 0x1
|
||||
|
||||
OAMOBJ_ATT1_VF_Pos = 0xD
|
||||
OAMOBJ_ATT1_VF_NOFLIP = 0x0
|
||||
OAMOBJ_ATT1_VF_FLIP = 0x1
|
||||
|
||||
OAMOBJ_ATT1_SZ_Pos = 0xE
|
||||
OAMOBJ_ATT1_SZ_Msk = 0x3
|
||||
|
||||
OAMOBJ_ATT2_TID_Pos = 0x0
|
||||
OAMOBJ_ATT2_TID_Msk = 0xFF
|
||||
|
||||
OAMOBJ_ATT2_PR_Pos = 0xA
|
||||
OAMOBJ_ATT2_PR_Msk = 0x3
|
||||
|
||||
OAMOBJ_ATT2_PB_Pos = 0xC
|
||||
OAMOBJ_ATT2_PB_Msk = 0xF
|
||||
)
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
// This is used for smoke tests for chips without an associated board.
|
||||
|
||||
func main() {
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
+11
-38
@@ -7,10 +7,7 @@ import (
|
||||
|
||||
var (
|
||||
err error
|
||||
message = "1234567887654321123456788765432112345678876543211234567887654321" +
|
||||
"1234567887654321123456788765432112345678876543211234567887654321" +
|
||||
"1234567887654321123456788765432112345678876543211234567887654321" +
|
||||
"1234567887654321123456788765432112345678876543211234567887654321"
|
||||
message = "1234567887654321123456788765432112345678876543211234567887654321"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -24,54 +21,30 @@ func main() {
|
||||
println("Flash erase block size:", machine.Flash.EraseBlockSize())
|
||||
println()
|
||||
|
||||
flash := machine.OpenFlashBuffer(machine.Flash, machine.FlashDataStart())
|
||||
original := make([]byte, len(message))
|
||||
saved := make([]byte, len(message))
|
||||
|
||||
// Read flash contents on start (data shall survive power off)
|
||||
println("Reading original data from flash:")
|
||||
_, err = machine.Flash.ReadAt(original, 0)
|
||||
print("Reading data from flash: ")
|
||||
_, err = flash.Read(original)
|
||||
checkError(err)
|
||||
println(string(original))
|
||||
|
||||
// erase flash
|
||||
println("Erasing flash...")
|
||||
needed := int64(len(message)) / machine.Flash.EraseBlockSize()
|
||||
if needed == 0 {
|
||||
// have to erase at least 1 block
|
||||
needed = 1
|
||||
}
|
||||
|
||||
err := machine.Flash.EraseBlocks(0, needed)
|
||||
checkError(err)
|
||||
|
||||
// Write the message to flash
|
||||
println("Writing new data to flash:")
|
||||
_, err = machine.Flash.WriteAt([]byte(message), 0)
|
||||
print("Writing data to flash: ")
|
||||
flash.Seek(0, 0) // rewind back to beginning
|
||||
_, err = flash.Write([]byte(message))
|
||||
checkError(err)
|
||||
println(string(message))
|
||||
|
||||
// Read back flash contents after write (verify data is the same as written)
|
||||
println("Reading data back from flash: ")
|
||||
_, err = machine.Flash.ReadAt(saved, 0)
|
||||
print("Reading data back from flash: ")
|
||||
flash.Seek(0, 0) // rewind back to beginning
|
||||
_, err = flash.Read(saved)
|
||||
checkError(err)
|
||||
if !equal(saved, []byte(message)) {
|
||||
println("data verify error")
|
||||
}
|
||||
|
||||
println(string(saved))
|
||||
println("Done.")
|
||||
}
|
||||
|
||||
func equal(a, b []byte) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
println()
|
||||
}
|
||||
|
||||
func checkError(err error) {
|
||||
|
||||
@@ -2,7 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"machine/usb/hid/joystick"
|
||||
"machine/usb/joystick"
|
||||
"math"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
// Example demonstrating I2C controller / target comms.
|
||||
//
|
||||
// To use this example, physically connect I2C0 and I2C1.
|
||||
// I2C0 will be used as the controller and I2C1 used as
|
||||
// the target.
|
||||
//
|
||||
// In this example, the target implements a simple memory
|
||||
// map, with the controller able to read and write the
|
||||
// memory.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
targetAddress = 0x11
|
||||
maxTxSize = 16
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Delay to enable USB monitor time to attach
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
// Controller uses default I2C pins and controller
|
||||
// mode is default
|
||||
err := controller.Configure(machine.I2CConfig{})
|
||||
if err != nil {
|
||||
panic("failed to config I2C0 as controller")
|
||||
}
|
||||
|
||||
// Target uses alternate pins and target mode is
|
||||
// explicit
|
||||
err = target.Configure(machine.I2CConfig{
|
||||
Mode: machine.I2CModeTarget,
|
||||
SCL: TARGET_SCL,
|
||||
SDA: TARGET_SDA,
|
||||
})
|
||||
if err != nil {
|
||||
panic("failed to config I2C1 as target")
|
||||
}
|
||||
|
||||
// Put welcome message directly into target memory
|
||||
copy(mem[0:], []byte("Hello World!"))
|
||||
err = target.Listen(targetAddress)
|
||||
if err != nil {
|
||||
panic("failed to listen as I2C target")
|
||||
}
|
||||
|
||||
// Start the target
|
||||
go targetMain()
|
||||
|
||||
// Read welcome message from target over I2C
|
||||
buf := make([]byte, 12)
|
||||
err = controller.Tx(targetAddress, []byte{0}, buf)
|
||||
if err != nil {
|
||||
println("failed to read welcome message over I2C")
|
||||
panic(err)
|
||||
}
|
||||
println("message from target:", string(buf))
|
||||
|
||||
// Write (1,2,3) to the target starting at memory address 3
|
||||
println("writing (1,2,3) @ 0x3")
|
||||
err = controller.Tx(targetAddress, []byte{3, 1, 2, 3}, nil)
|
||||
if err != nil {
|
||||
println("failed to write to I2C target")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
time.Sleep(100 * time.Millisecond) // Wait for target to process write
|
||||
println("mem:", mem[0], mem[1], mem[2], mem[3], mem[4], mem[5])
|
||||
|
||||
// Read memory address 4 from target, which should be the value 2
|
||||
buf = make([]byte, 1)
|
||||
err = controller.Tx(targetAddress, []byte{4}, buf[:1])
|
||||
if err != nil {
|
||||
println("failed to read from I2C target")
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if buf[0] != 2 {
|
||||
panic("read incorrect value from I2C target")
|
||||
}
|
||||
|
||||
println("all done!")
|
||||
for {
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
// -- target ---
|
||||
|
||||
var (
|
||||
mem [256]byte
|
||||
)
|
||||
|
||||
// targetMain implements the 'main loop' for an I2C target
|
||||
func targetMain() {
|
||||
buf := make([]byte, maxTxSize)
|
||||
var ptr uint8
|
||||
|
||||
for {
|
||||
evt, n, err := target.WaitForEvent(buf)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
switch evt {
|
||||
case machine.I2CReceive:
|
||||
if n > 0 {
|
||||
ptr = buf[0]
|
||||
}
|
||||
|
||||
for o := 1; o < n; o++ {
|
||||
mem[ptr] = buf[o]
|
||||
ptr++
|
||||
}
|
||||
|
||||
case machine.I2CRequest:
|
||||
target.Reply(mem[ptr:256])
|
||||
|
||||
case machine.I2CFinish:
|
||||
// nothing to do
|
||||
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
//go:build feather_nrf52840
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
TARGET_SCL = machine.A5
|
||||
TARGET_SDA = machine.A4
|
||||
)
|
||||
|
||||
var (
|
||||
controller = machine.I2C0
|
||||
target = machine.I2C1
|
||||
)
|
||||
@@ -1,15 +0,0 @@
|
||||
//go:build rp2040
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
TARGET_SCL = machine.GPIO25
|
||||
TARGET_SDA = machine.GPIO24
|
||||
)
|
||||
|
||||
var (
|
||||
controller = machine.I2C1
|
||||
target = machine.I2C0
|
||||
)
|
||||
@@ -1,11 +0,0 @@
|
||||
//go:build arduino
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
button = machine.D2
|
||||
buttonMode = machine.PinInputPullup
|
||||
buttonPinChange = machine.PinRising
|
||||
)
|
||||
@@ -5,7 +5,6 @@ package main
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
button = machine.BUTTON
|
||||
buttonMode = machine.PinInputPulldown
|
||||
buttonPinChange = machine.PinFalling
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@ package main
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
button = machine.BUTTON
|
||||
buttonMode = machine.PinInputPullup
|
||||
buttonPinChange = machine.PinRising
|
||||
)
|
||||
|
||||
@@ -8,14 +8,18 @@ package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"runtime/volatile"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
led = machine.LED
|
||||
button = machine.BUTTON
|
||||
led = machine.LED
|
||||
)
|
||||
|
||||
func main() {
|
||||
var lightLed volatile.Register8
|
||||
lightLed.Set(0)
|
||||
|
||||
// Configure the LED, defaulting to on (usually setting the pin to low will
|
||||
// turn the LED on).
|
||||
@@ -29,7 +33,13 @@ func main() {
|
||||
|
||||
// Set an interrupt on this pin.
|
||||
err := button.SetInterrupt(buttonPinChange, func(machine.Pin) {
|
||||
led.Set(!led.Get())
|
||||
if lightLed.Get() != 0 {
|
||||
lightLed.Set(0)
|
||||
led.Low()
|
||||
} else {
|
||||
lightLed.Set(1)
|
||||
led.High()
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
println("could not configure pin interrupt:", err.Error())
|
||||
|
||||
@@ -5,7 +5,6 @@ package main
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
button = machine.BUTTON
|
||||
buttonMode = machine.PinInputPulldown
|
||||
buttonPinChange = machine.PinRising | machine.PinFalling
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@ package main
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
button = machine.BUTTON
|
||||
buttonMode = machine.PinInput
|
||||
buttonPinChange = machine.PinFalling
|
||||
)
|
||||
|
||||
@@ -83,7 +83,7 @@ func in_ram() uintptr {
|
||||
return device.AsmFull("MOV {}, PC", nil)
|
||||
}
|
||||
|
||||
// 'go:noinline' used here to prevent function being 'inlined' into main()
|
||||
// go:noinline used here to prevent function being 'inlined' into main()
|
||||
// so it appears in objdump output. In normal use, go:inline is not
|
||||
// required for functions running from flash (flash is the default).
|
||||
//
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
package main
|
||||
|
||||
// This example demonstrates how to set the system time.
|
||||
//
|
||||
// Usually, boards don't keep time on power cycles and restarts, it resets to Unix epoch.
|
||||
// The system time can be set by calling runtime.AdjustTimeOffset().
|
||||
//
|
||||
// Possible time sources: an external RTC clock or network (WiFi access point or NTP server)
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
const myTime = "2006-01-02T15:04:05Z" // this is an example time you source somewhere
|
||||
|
||||
func main() {
|
||||
|
||||
// measure how many nanoseconds the internal clock is behind
|
||||
timeOfMeasurement := time.Now()
|
||||
actualTime, _ := time.Parse(time.RFC3339, myTime)
|
||||
offset := actualTime.Sub(timeOfMeasurement)
|
||||
|
||||
// adjust internal clock by adding the offset to the internal clock
|
||||
runtime.AdjustTimeOffset(int64(offset))
|
||||
|
||||
for {
|
||||
fmt.Printf("%v\r\n", time.Now().Format(time.RFC3339))
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"machine/usb/adc/midi"
|
||||
|
||||
"machine/usb/midi"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -15,11 +15,12 @@ func main() {
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
button := machine.BUTTON
|
||||
button.Configure(machine.PinConfig{Mode: machine.PinInputPulldown})
|
||||
button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||
|
||||
m := midi.Port()
|
||||
m.SetHandler(func(b []byte) {
|
||||
led.Set(!led.Get())
|
||||
fmt.Printf("% X\r\n", b)
|
||||
m.Write(b)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
//sleep for 2 secs for console
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
config := machine.WatchdogConfig{
|
||||
TimeoutMillis: 1000,
|
||||
}
|
||||
|
||||
println("configuring watchdog for max 1 second updates")
|
||||
machine.Watchdog.Configure(config)
|
||||
|
||||
// From this point the watchdog is running and Update must be
|
||||
// called periodically, per the config
|
||||
machine.Watchdog.Start()
|
||||
|
||||
// This loop should complete because watchdog update is called
|
||||
// every 100ms.
|
||||
start := time.Now()
|
||||
println("updating watchdog for 3 seconds")
|
||||
for i := 0; i < 30; i++ {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
machine.Watchdog.Update()
|
||||
fmt.Printf("alive @ %v\n", time.Now().Sub(start))
|
||||
}
|
||||
|
||||
// This loop should cause a watchdog reset after 1s since
|
||||
// there is no update call.
|
||||
start = time.Now()
|
||||
println("entering tight loop")
|
||||
for {
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
fmt.Printf("alive @ %v\n", time.Now().Sub(start))
|
||||
}
|
||||
}
|
||||
@@ -251,13 +251,3 @@ func IndexRabinKarp(s, substr string) int {
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// MakeNoZero makes a slice of length and capacity n without zeroing the bytes.
|
||||
// It is the caller's responsibility to ensure uninitialized bytes
|
||||
// do not leak to the end user.
|
||||
func MakeNoZero(n int) []byte {
|
||||
// Note: this does zero the buffer even though that's not necessary.
|
||||
// For performance reasons we might want to change this (similar to the
|
||||
// malloc function implemented in the runtime).
|
||||
return make([]byte, n)
|
||||
}
|
||||
|
||||
@@ -114,9 +114,9 @@ tinygo_swapTask:
|
||||
pop {r4-r11, pc}
|
||||
#else
|
||||
pop {r4-r7}
|
||||
.cfi_def_cfa_offset 5*4
|
||||
.cfi_def_cfa_offset 5*9
|
||||
pop {r0-r3}
|
||||
.cfi_def_cfa_offset 1*4
|
||||
.cfi_def_cfa_offset 1*9
|
||||
mov r8, r0
|
||||
mov r9, r1
|
||||
mov r10, r2
|
||||
|
||||
@@ -9,5 +9,4 @@ type ADCConfig struct {
|
||||
Reference uint32 // analog reference voltage (AREF) in millivolts
|
||||
Resolution uint32 // number of bits for a single conversion (e.g., 8, 10, 12)
|
||||
Samples uint32 // number of samples for a single conversion (e.g., 4, 8, 16, 32)
|
||||
SampleTime uint32 // sample time, in microseconds (µs)
|
||||
}
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
//go:build ae_rp2040
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/rp"
|
||||
"runtime/interrupt"
|
||||
)
|
||||
|
||||
// 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
|
||||
GP29 Pin = GPIO29
|
||||
|
||||
// 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
|
||||
)
|
||||
|
||||
// UART on the RP2040
|
||||
var (
|
||||
UART0 = &_UART0
|
||||
_UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART0,
|
||||
}
|
||||
|
||||
UART1 = &_UART1
|
||||
_UART1 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: rp.UART1,
|
||||
}
|
||||
)
|
||||
|
||||
var DefaultUART = UART0
|
||||
|
||||
func init() {
|
||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||
UART1.Interrupt = interrupt.New(rp.IRQ_UART1_IRQ, _UART1.handleInterrupt)
|
||||
}
|
||||
|
||||
// USB identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "AE-RP2040"
|
||||
usb_STRING_MANUFACTURER = "AKIZUKI DENSHI"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x2E8A
|
||||
usb_PID uint16 = 0x000A
|
||||
)
|
||||
@@ -1,80 +0,0 @@
|
||||
//go:build bluemicro840
|
||||
|
||||
package machine
|
||||
|
||||
const HasLowFrequencyCrystal = true
|
||||
|
||||
// GPIO Pins
|
||||
const (
|
||||
D006 = P0_06
|
||||
D008 = P0_08
|
||||
D015 = P0_15
|
||||
D017 = P0_17
|
||||
D020 = P0_20
|
||||
D013 = P0_13
|
||||
D024 = P0_24
|
||||
D009 = P0_09
|
||||
D010 = P0_10
|
||||
D106 = P1_06
|
||||
|
||||
D031 = P0_31 // AIN7; P0.31 (AIN7) is used to read the voltage of the battery via ADC. It can’t be used for any other function.
|
||||
D012 = P0_12 // VCC 3.3V; P0.12 on VCC shuts off the power to VCC when you set it to high; This saves on battery immensely for LEDs of all kinds that eat power even when off
|
||||
|
||||
D030 = P0_30
|
||||
D026 = P0_26
|
||||
D029 = P0_29
|
||||
D002 = P0_02
|
||||
D113 = P1_13
|
||||
D003 = P0_03
|
||||
D028 = P0_28
|
||||
D111 = P1_11
|
||||
)
|
||||
|
||||
// Analog Pins
|
||||
const (
|
||||
AIN0 = P0_02
|
||||
AIN1 = P0_03
|
||||
AIN2 = P0_04 // Not Connected
|
||||
AIN3 = P0_05 // Not Connected
|
||||
AIN4 = P0_28
|
||||
AIN5 = P0_29
|
||||
AIN6 = P0_30
|
||||
AIN7 = P0_31 // Battery
|
||||
)
|
||||
|
||||
const (
|
||||
LED1 Pin = P1_04 // Red LED
|
||||
LED2 Pin = P1_10 // Blue LED
|
||||
LED Pin = LED1
|
||||
)
|
||||
|
||||
// UART0 pins (logical UART1) - Maps to same location as Pro Micro
|
||||
const (
|
||||
UART_RX_PIN = P0_08
|
||||
UART_TX_PIN = P0_06
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
SDA_PIN = P0_15 // I2C0 external
|
||||
SCL_PIN = P0_17 // I2C0 external
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI0_SCK_PIN = P1_13 // SCK
|
||||
SPI0_SDI_PIN = P0_03 // SDI
|
||||
SPI0_SDO_PIN = P0_28 // SDO
|
||||
|
||||
)
|
||||
|
||||
// USB CDC identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "bluemicro840"
|
||||
usb_STRING_MANUFACTURER = "BlueMicro"
|
||||
)
|
||||
|
||||
var (
|
||||
usb_VID uint16 = 0x1d50
|
||||
usb_PID uint16 = 0x6161
|
||||
)
|
||||
@@ -1,117 +0,0 @@
|
||||
//go:build m5stick_c
|
||||
|
||||
// This file contains the pin mapping for the M5STACK M5Stick-C device.
|
||||
// doc: https://docs.m5stack.com/en/core/m5stickc
|
||||
|
||||
package machine
|
||||
|
||||
const (
|
||||
// HAT | HY2.0-4P
|
||||
// |
|
||||
// GND | GND
|
||||
// 5V OUT | VOUT
|
||||
// G26 | G32 SDA
|
||||
// G36 | G33 SCL
|
||||
// G0 |
|
||||
// BAT |
|
||||
// 3V3 |
|
||||
// 5V IN |
|
||||
|
||||
IO0 = GPIO0 // CLK
|
||||
IO1 = GPIO1 // U0TXD
|
||||
IO2 = GPIO2
|
||||
IO3 = GPIO3 // U0RXD
|
||||
IO4 = GPIO4
|
||||
IO5 = GPIO5 // TFT_CS LCD_SS SPI0_SS
|
||||
IO6 = GPIO6
|
||||
IO7 = GPIO7
|
||||
IO8 = GPIO8
|
||||
IO9 = GPIO9 // IR
|
||||
IO10 = GPIO10 // LED
|
||||
IO11 = GPIO11
|
||||
IO12 = GPIO12
|
||||
IO13 = GPIO13 // TFT_CLK LCD_SCK SPI0_SCK
|
||||
IO14 = GPIO14
|
||||
IO15 = GPIO15 // TFT_MOSI LCD_MOSI SPI0_MOSI
|
||||
IO16 = GPIO16
|
||||
IO17 = GPIO17
|
||||
IO18 = GPIO18 // TFT_RST LCD_RST
|
||||
IO19 = GPIO19
|
||||
IO21 = GPIO21 // SDA0
|
||||
IO22 = GPIO22 // SCL0
|
||||
IO23 = GPIO23 // TFT_DC LCD_DC
|
||||
IO25 = GPIO25 // - DAC1
|
||||
IO26 = GPIO26 // HAT DAC2
|
||||
IO27 = GPIO27
|
||||
IO32 = GPIO32 // SDA1 / PIN 32 / RXD2
|
||||
IO33 = GPIO33 // SCL1 / PIN 33 / TXD2
|
||||
IO34 = GPIO34 // MIC_DATA
|
||||
IO35 = GPIO35 // IRQ0 ADC1
|
||||
IO36 = GPIO36 // HAT ADC2 LCD_MISO SPI0_MISO
|
||||
IO37 = GPIO37 // BUTTON_A, BUTTON_HOME, BUTTON
|
||||
IO38 = GPIO38
|
||||
IO39 = GPIO39 // BUTTON_B, BUTTON_RST
|
||||
)
|
||||
|
||||
const (
|
||||
// Buttons
|
||||
BUTTON_A = IO37
|
||||
BUTTON_B = IO39
|
||||
BUTTON_HOME = BUTTON_A
|
||||
BUTTON_RST = BUTTON_B
|
||||
BUTTON = BUTTON_A
|
||||
|
||||
// LED
|
||||
IR = IO9
|
||||
LED = IO10
|
||||
)
|
||||
|
||||
// SPI pins
|
||||
const (
|
||||
SPI0_SCK_PIN = IO13
|
||||
SPI0_SDO_PIN = IO15
|
||||
SPI0_CS0_PIN = IO5
|
||||
|
||||
// LCD ()
|
||||
LCD_SCK_PIN = SPI0_SCK_PIN
|
||||
LCD_SDO_PIN = SPI0_SDO_PIN
|
||||
LCD_SS_PIN = SPI0_CS0_PIN
|
||||
LCD_DC_PIN = IO23
|
||||
LCD_RST_PIN = IO18
|
||||
)
|
||||
|
||||
// I2C pins
|
||||
const (
|
||||
// Internal I2C (AXP192 / BM8563 / MPU6886)
|
||||
SDA0_PIN = IO21
|
||||
SCL0_PIN = IO22
|
||||
|
||||
// External I2C (GROOVE PORT)
|
||||
SDA1_PIN = IO32
|
||||
SCL1_PIN = IO33
|
||||
|
||||
SDA_PIN = SDA1_PIN
|
||||
SCL_PIN = SCL1_PIN
|
||||
)
|
||||
|
||||
// ADC pins
|
||||
const (
|
||||
ADC1 Pin = IO35
|
||||
ADC2 Pin = IO36
|
||||
)
|
||||
|
||||
// DAC pins
|
||||
const (
|
||||
DAC1 Pin = IO25
|
||||
DAC2 Pin = IO26
|
||||
)
|
||||
|
||||
// UART pins
|
||||
const (
|
||||
// UART0 (CP2104)
|
||||
UART0_TX_PIN = IO1
|
||||
UART0_RX_PIN = IO3
|
||||
|
||||
UART_TX_PIN = UART0_TX_PIN
|
||||
UART_RX_PIN = UART0_RX_PIN
|
||||
)
|
||||
@@ -16,7 +16,6 @@ const (
|
||||
|
||||
const (
|
||||
SWITCH = GPIO0
|
||||
BUTTON = GPIO0
|
||||
|
||||
KEY1 = GPIO1
|
||||
KEY2 = GPIO2
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build pinetime
|
||||
//go:build pinetime_devkit0
|
||||
|
||||
package machine
|
||||
|
||||
@@ -17,10 +17,13 @@ const (
|
||||
LED = LED1
|
||||
)
|
||||
|
||||
// The PineTime doesn't have a UART output.
|
||||
// Additionally, leaving the UART on results in a pretty big current drain.
|
||||
var DefaultUART = UART0
|
||||
|
||||
// UART pins for PineTime. Note that RX is set to NoPin as RXD is not listed in
|
||||
// the PineTime schematic 1.0:
|
||||
// http://files.pine64.org/doc/PineTime/PineTime%20Port%20Assignment%20rev1.0.pdf
|
||||
const (
|
||||
UART_TX_PIN Pin = NoPin
|
||||
UART_TX_PIN Pin = 11 // TP29 (TXD)
|
||||
UART_RX_PIN Pin = NoPin
|
||||
)
|
||||
|
||||
@@ -96,7 +96,3 @@ var (
|
||||
usb_VID uint16 = 0x2886
|
||||
usb_PID uint16 = 0x802F
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultUART = UART1
|
||||
)
|
||||
|
||||
@@ -64,3 +64,82 @@ type BlockDevice interface {
|
||||
// EraseBlockSize to map addresses to blocks.
|
||||
EraseBlocks(start, len int64) error
|
||||
}
|
||||
|
||||
// FlashBuffer implements the ReadWriteCloser interface using the BlockDevice interface.
|
||||
type FlashBuffer struct {
|
||||
b BlockDevice
|
||||
|
||||
// start is actual address
|
||||
start uintptr
|
||||
|
||||
// offset is relative to start
|
||||
offset uintptr
|
||||
}
|
||||
|
||||
// OpenFlashBuffer opens a FlashBuffer.
|
||||
func OpenFlashBuffer(b BlockDevice, address uintptr) *FlashBuffer {
|
||||
return &FlashBuffer{b: b, start: address}
|
||||
}
|
||||
|
||||
// Read data from a FlashBuffer.
|
||||
func (fl *FlashBuffer) Read(p []byte) (n int, err error) {
|
||||
n, err = fl.b.ReadAt(p, int64(fl.offset))
|
||||
fl.offset += uintptr(n)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Write data to a FlashBuffer.
|
||||
func (fl *FlashBuffer) Write(p []byte) (n int, err error) {
|
||||
// any new pages needed?
|
||||
// NOTE probably will not work as expected if you try to write over page boundary
|
||||
// of pages with different sizes.
|
||||
pagesize := uintptr(fl.b.EraseBlockSize())
|
||||
|
||||
// calculate currentPageBlock relative to fl.start, meaning that
|
||||
// block 0 -> fl.start
|
||||
// block 1 -> fl.start + pagesize
|
||||
// block 2 -> fl.start + pagesize*2
|
||||
// ...
|
||||
currentPageBlock := (fl.start + fl.offset - FlashDataStart()) + (pagesize-1)/pagesize
|
||||
lastPageBlockNeeded := (fl.start + fl.offset + uintptr(len(p)) - FlashDataStart()) + (pagesize-1)/pagesize
|
||||
|
||||
// erase enough blocks to hold the data
|
||||
if err := fl.b.EraseBlocks(int64(currentPageBlock), int64(lastPageBlockNeeded-currentPageBlock)); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
// write the data
|
||||
for i := 0; i < len(p); i += int(pagesize) {
|
||||
var last int = i + int(pagesize)
|
||||
if i+int(pagesize) > len(p) {
|
||||
last = len(p)
|
||||
}
|
||||
|
||||
_, err := fl.b.WriteAt(p[i:last], int64(fl.offset))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
fl.offset += uintptr(len(p[i:last]))
|
||||
}
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
// Close the FlashBuffer.
|
||||
func (fl *FlashBuffer) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Seek implements io.Seeker interface, but with limitations.
|
||||
// You can only seek relative to the start.
|
||||
// Also, you cannot use seek before write operations, only read.
|
||||
func (fl *FlashBuffer) Seek(offset int64, whence int) (int64, error) {
|
||||
if whence != io.SeekStart {
|
||||
panic("you can only Seek relative to Start")
|
||||
}
|
||||
|
||||
fl.offset = uintptr(offset)
|
||||
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
@@ -23,37 +23,6 @@ var (
|
||||
errI2CSignalStopTimeout = errors.New("I2C timeout on signal stop")
|
||||
errI2CAckExpected = errors.New("I2C error: expected ACK not NACK")
|
||||
errI2CBusError = errors.New("I2C bus error")
|
||||
errI2COverflow = errors.New("I2C receive buffer overflow")
|
||||
errI2COverread = errors.New("I2C transmit buffer overflow")
|
||||
)
|
||||
|
||||
// I2CTargetEvent reflects events on the I2C bus
|
||||
type I2CTargetEvent uint8
|
||||
|
||||
const (
|
||||
// I2CReceive indicates target has received a message from the controller.
|
||||
I2CReceive I2CTargetEvent = iota
|
||||
|
||||
// I2CRequest indicates the controller is expecting a message from the target.
|
||||
I2CRequest
|
||||
|
||||
// I2CFinish indicates the controller has ended the transaction.
|
||||
//
|
||||
// I2C controllers can chain multiple receive/request messages without
|
||||
// relinquishing the bus by doing 'restarts'. I2CFinish indicates the
|
||||
// bus has been relinquished by an I2C 'stop'.
|
||||
I2CFinish
|
||||
)
|
||||
|
||||
// I2CMode determines if an I2C peripheral is in Controller or Target mode.
|
||||
type I2CMode int
|
||||
|
||||
const (
|
||||
// I2CModeController represents an I2C peripheral in controller mode.
|
||||
I2CModeController I2CMode = iota
|
||||
|
||||
// I2CModeTarget represents an I2C peripheral in target mode.
|
||||
I2CModeTarget
|
||||
)
|
||||
|
||||
// WriteRegister transmits first the register and then the data to the
|
||||
|
||||
@@ -97,7 +97,7 @@ func (i2c *I2C) stop() {
|
||||
}
|
||||
|
||||
// writeByte writes a single byte to the I2C bus.
|
||||
func (i2c *I2C) writeByte(data byte) error {
|
||||
func (i2c *I2C) writeByte(data byte) {
|
||||
// Write data to register.
|
||||
avr.TWDR.Set(data)
|
||||
|
||||
@@ -107,7 +107,6 @@ func (i2c *I2C) writeByte(data byte) error {
|
||||
// Wait till data is transmitted.
|
||||
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// readByte reads a single byte from the I2C bus.
|
||||
@@ -191,7 +190,7 @@ func (uart *UART) handleInterrupt(intr interrupt.Interrupt) {
|
||||
}
|
||||
|
||||
// WriteByte writes a byte of data to the UART.
|
||||
func (uart *UART) writeByte(c byte) error {
|
||||
func (uart *UART) WriteByte(c byte) error {
|
||||
// Wait until UART buffer is not busy.
|
||||
for !uart.statusRegA.HasBits(avr.UCSR0A_UDRE0) {
|
||||
}
|
||||
@@ -199,8 +198,6 @@ func (uart *UART) writeByte(c byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uart *UART) flush() {}
|
||||
|
||||
// SPIConfig is used to store config info for SPI.
|
||||
type SPIConfig struct {
|
||||
Frequency uint32
|
||||
|
||||
@@ -466,107 +466,3 @@ var SPI0 = SPI{
|
||||
sdo: PB3,
|
||||
sdi: PB4,
|
||||
cs: PB2}
|
||||
|
||||
// Pin Change Interrupts
|
||||
type PinChange uint8
|
||||
|
||||
const (
|
||||
PinRising PinChange = 1 << iota
|
||||
PinFalling
|
||||
PinToggle = PinRising | PinFalling
|
||||
)
|
||||
|
||||
func (pin Pin) SetInterrupt(pinChange PinChange, callback func(Pin)) (err error) {
|
||||
|
||||
switch {
|
||||
case pin >= PB0 && pin <= PB7:
|
||||
// PCMSK0 - PCINT0-7
|
||||
pinStates[0] = avr.PINB.Get()
|
||||
pinIndex := pin - PB0
|
||||
if pinChange&PinRising > 0 {
|
||||
pinCallbacks[0][pinIndex][0] = callback
|
||||
}
|
||||
if pinChange&PinFalling > 0 {
|
||||
pinCallbacks[0][pinIndex][1] = callback
|
||||
}
|
||||
if callback != nil {
|
||||
avr.PCMSK0.SetBits(1 << pinIndex)
|
||||
} else {
|
||||
avr.PCMSK0.ClearBits(1 << pinIndex)
|
||||
}
|
||||
avr.PCICR.SetBits(avr.PCICR_PCIE0)
|
||||
interrupt.New(avr.IRQ_PCINT0, handlePCINT0Interrupts)
|
||||
case pin >= PC0 && pin <= PC7:
|
||||
// PCMSK1 - PCINT8-14
|
||||
pinStates[1] = avr.PINC.Get()
|
||||
pinIndex := pin - PC0
|
||||
if pinChange&PinRising > 0 {
|
||||
pinCallbacks[1][pinIndex][0] = callback
|
||||
}
|
||||
if pinChange&PinFalling > 0 {
|
||||
pinCallbacks[1][pinIndex][1] = callback
|
||||
}
|
||||
if callback != nil {
|
||||
avr.PCMSK1.SetBits(1 << pinIndex)
|
||||
} else {
|
||||
avr.PCMSK1.ClearBits(1 << pinIndex)
|
||||
}
|
||||
avr.PCICR.SetBits(avr.PCICR_PCIE1)
|
||||
interrupt.New(avr.IRQ_PCINT1, handlePCINT1Interrupts)
|
||||
case pin >= PD0 && pin <= PD7:
|
||||
// PCMSK2 - PCINT16-23
|
||||
pinStates[2] = avr.PIND.Get()
|
||||
pinIndex := pin - PD0
|
||||
if pinChange&PinRising > 0 {
|
||||
pinCallbacks[2][pinIndex][0] = callback
|
||||
}
|
||||
if pinChange&PinFalling > 0 {
|
||||
pinCallbacks[2][pinIndex][1] = callback
|
||||
}
|
||||
if callback != nil {
|
||||
avr.PCMSK2.SetBits(1 << pinIndex)
|
||||
} else {
|
||||
avr.PCMSK2.ClearBits(1 << pinIndex)
|
||||
}
|
||||
avr.PCICR.SetBits(avr.PCICR_PCIE2)
|
||||
interrupt.New(avr.IRQ_PCINT2, handlePCINT2Interrupts)
|
||||
default:
|
||||
return ErrInvalidInputPin
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var pinCallbacks [3][8][2]func(Pin)
|
||||
var pinStates [3]uint8
|
||||
|
||||
func handlePCINTInterrupts(intr uint8, port *volatile.Register8) {
|
||||
current := port.Get()
|
||||
change := pinStates[intr] ^ current
|
||||
pinStates[intr] = current
|
||||
for i := uint8(0); i < 8; i++ {
|
||||
if (change>>i)&0x01 != 0x01 {
|
||||
continue
|
||||
}
|
||||
pin := Pin(intr*8 + i)
|
||||
value := pin.Get()
|
||||
if value && pinCallbacks[intr][i][0] != nil {
|
||||
pinCallbacks[intr][i][0](pin)
|
||||
}
|
||||
if !value && pinCallbacks[intr][i][1] != nil {
|
||||
pinCallbacks[intr][i][1](pin)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handlePCINT0Interrupts(intr interrupt.Interrupt) {
|
||||
handlePCINTInterrupts(0, avr.PINB)
|
||||
}
|
||||
|
||||
func handlePCINT1Interrupts(intr interrupt.Interrupt) {
|
||||
handlePCINTInterrupts(1, avr.PINC)
|
||||
}
|
||||
|
||||
func handlePCINT2Interrupts(intr interrupt.Interrupt) {
|
||||
handlePCINTInterrupts(2, avr.PIND)
|
||||
}
|
||||
|
||||
@@ -626,7 +626,7 @@ func (uart *UART) SetBaudRate(br uint32) {
|
||||
}
|
||||
|
||||
// WriteByte writes a byte of data to the UART.
|
||||
func (uart *UART) writeByte(c byte) error {
|
||||
func (uart *UART) WriteByte(c byte) error {
|
||||
// wait until ready to receive
|
||||
for !uart.Bus.INTFLAG.HasBits(sam.SERCOM_USART_INTFLAG_DRE) {
|
||||
}
|
||||
@@ -634,8 +634,6 @@ func (uart *UART) writeByte(c byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uart *UART) flush() {}
|
||||
|
||||
// handleInterrupt should be called from the appropriate interrupt handler for
|
||||
// this UART instance.
|
||||
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
||||
@@ -1912,12 +1910,12 @@ func (f flashBlockDevice) EraseBlocks(start, len int64) error {
|
||||
|
||||
// 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 {
|
||||
paddingNeeded := f.WriteBlockSize() - (int64(len(p)) % f.WriteBlockSize())
|
||||
if paddingNeeded == 0 {
|
||||
return p
|
||||
}
|
||||
|
||||
padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow))
|
||||
padding := bytes.Repeat([]byte{0xff}, int(paddingNeeded))
|
||||
return append(p, padding...)
|
||||
}
|
||||
|
||||
|
||||
@@ -139,9 +139,8 @@ func handleUSBIRQ(intr interrupt.Interrupt) {
|
||||
setup := usb.NewSetup(udd_ep_out_cache_buffer[0][:])
|
||||
|
||||
// Clear the Bank 0 ready flag on Control OUT
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0]))))
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
setEPSTATUSCLR(0, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
ok := false
|
||||
if (setup.BmRequestType & usb.REQUEST_TYPE) == usb.REQUEST_STANDARD {
|
||||
@@ -345,6 +344,15 @@ func sendUSBPacket(ep uint32, data []byte, maxsize uint16) {
|
||||
func ReceiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
|
||||
var b [cdcLineInfoSize]byte
|
||||
|
||||
// address
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0]))))
|
||||
|
||||
// set byte count to zero
|
||||
usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.ClearBits(usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos)
|
||||
|
||||
// set ready for next data
|
||||
setEPSTATUSCLR(0, sam.USB_DEVICE_EPSTATUSCLR_BK0RDY)
|
||||
|
||||
// Wait until OUT transfer is ready.
|
||||
timeout := 300000
|
||||
for (getEPSTATUS(0) & sam.USB_DEVICE_EPSTATUS_BK0RDY) == 0 {
|
||||
|
||||
@@ -46,14 +46,10 @@ func init() {
|
||||
// Return the register and mask to enable a given GPIO pin. This can be used to
|
||||
// implement bit-banged drivers.
|
||||
func (p Pin) PortMaskSet() (*uint32, uint32) {
|
||||
// Note: using PORT_IOBUS for faster pin accesses.
|
||||
// The regular PORT registers appear to take around 4 clock cycles to store,
|
||||
// which is longer than the ws2812 driver expects. The IOBUS is is fast
|
||||
// enough to avoid this issue.
|
||||
if p < 32 {
|
||||
return &sam.PORT_IOBUS.OUTSET0.Reg, 1 << uint8(p)
|
||||
return &sam.PORT.OUTSET0.Reg, 1 << uint8(p)
|
||||
} else {
|
||||
return &sam.PORT_IOBUS.OUTSET1.Reg, 1 << uint8(p-32)
|
||||
return &sam.PORT.OUTSET1.Reg, 1 << uint8(p-32)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,9 +57,9 @@ func (p Pin) PortMaskSet() (*uint32, uint32) {
|
||||
// implement bit-banged drivers.
|
||||
func (p Pin) PortMaskClear() (*uint32, uint32) {
|
||||
if p < 32 {
|
||||
return &sam.PORT_IOBUS.OUTCLR0.Reg, 1 << uint8(p)
|
||||
return &sam.PORT.OUTCLR0.Reg, 1 << uint8(p)
|
||||
} else {
|
||||
return &sam.PORT_IOBUS.OUTCLR1.Reg, 1 << uint8(p-32)
|
||||
return &sam.PORT.OUTCLR1.Reg, 1 << uint8(p-32)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+46
-130
@@ -749,10 +749,36 @@ func (a ADC) Configure(config ADCConfig) {
|
||||
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_CTRLB) {
|
||||
} // wait for sync
|
||||
|
||||
adc.CTRLA.SetBits(sam.ADC_CTRLA_PRESCALER_DIV32 << sam.ADC_CTRLA_PRESCALER_Pos)
|
||||
var resolution uint32
|
||||
switch config.Resolution {
|
||||
case 8:
|
||||
resolution = sam.ADC_CTRLB_RESSEL_8BIT
|
||||
case 10:
|
||||
resolution = sam.ADC_CTRLB_RESSEL_10BIT
|
||||
case 12:
|
||||
resolution = sam.ADC_CTRLB_RESSEL_12BIT
|
||||
case 16:
|
||||
resolution = sam.ADC_CTRLB_RESSEL_16BIT
|
||||
default:
|
||||
resolution = sam.ADC_CTRLB_RESSEL_12BIT
|
||||
}
|
||||
adc.CTRLB.SetBits(uint16(resolution << sam.ADC_CTRLB_RESSEL_Pos))
|
||||
adc.SAMPCTRL.Set(5) // sampling Time Length
|
||||
|
||||
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_SAMPCTRL) {
|
||||
} // wait for sync
|
||||
|
||||
// No Negative input (Internal Ground)
|
||||
adc.INPUTCTRL.Set(sam.ADC_INPUTCTRL_MUXNEG_GND << sam.ADC_INPUTCTRL_MUXNEG_Pos)
|
||||
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_INPUTCTRL) {
|
||||
} // wait for sync
|
||||
|
||||
// Averaging (see datasheet table in AVGCTRL register description)
|
||||
var resolution uint32 = sam.ADC_CTRLB_RESSEL_16BIT
|
||||
var samples uint32
|
||||
switch config.Samples {
|
||||
case 1:
|
||||
samples = sam.ADC_AVGCTRL_SAMPLENUM_1
|
||||
case 2:
|
||||
samples = sam.ADC_AVGCTRL_SAMPLENUM_2
|
||||
case 4:
|
||||
@@ -774,39 +800,11 @@ func (a ADC) Configure(config ADCConfig) {
|
||||
case 1024:
|
||||
samples = sam.ADC_AVGCTRL_SAMPLENUM_1024
|
||||
default: // 1 sample only (no oversampling nor averaging), adjusting result by 0
|
||||
// Resolutions less than 16 bits only make sense when sampling only
|
||||
// once. Resulting ADC values become erratic when using both
|
||||
// multi-sampling and less than 16 bits of resolution.
|
||||
samples = sam.ADC_AVGCTRL_SAMPLENUM_1
|
||||
switch config.Resolution {
|
||||
case 8:
|
||||
resolution = sam.ADC_CTRLB_RESSEL_8BIT
|
||||
case 10:
|
||||
resolution = sam.ADC_CTRLB_RESSEL_10BIT
|
||||
case 12:
|
||||
resolution = sam.ADC_CTRLB_RESSEL_12BIT
|
||||
case 16:
|
||||
resolution = sam.ADC_CTRLB_RESSEL_16BIT
|
||||
default:
|
||||
resolution = sam.ADC_CTRLB_RESSEL_12BIT
|
||||
}
|
||||
}
|
||||
|
||||
adc.AVGCTRL.Set(uint8(samples<<sam.ADC_AVGCTRL_SAMPLENUM_Pos) |
|
||||
(0 << sam.ADC_AVGCTRL_ADJRES_Pos))
|
||||
|
||||
adc.CTRLA.SetBits(sam.ADC_CTRLA_PRESCALER_DIV32 << sam.ADC_CTRLA_PRESCALER_Pos)
|
||||
adc.CTRLB.SetBits(uint16(resolution << sam.ADC_CTRLB_RESSEL_Pos))
|
||||
adc.SAMPCTRL.Set(5) // sampling Time Length
|
||||
|
||||
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_SAMPCTRL) {
|
||||
} // wait for sync
|
||||
|
||||
// No Negative input (Internal Ground)
|
||||
adc.INPUTCTRL.Set(sam.ADC_INPUTCTRL_MUXNEG_GND << sam.ADC_INPUTCTRL_MUXNEG_Pos)
|
||||
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_INPUTCTRL) {
|
||||
} // wait for sync
|
||||
|
||||
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_AVGCTRL) {
|
||||
} // wait for sync
|
||||
for adc.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_REFCTRL) {
|
||||
@@ -873,24 +871,10 @@ func (a ADC) Get() uint16 {
|
||||
val = val << 8
|
||||
case sam.ADC_CTRLB_RESSEL_10BIT:
|
||||
val = val << 6
|
||||
case sam.ADC_CTRLB_RESSEL_16BIT:
|
||||
val = val << 4
|
||||
case sam.ADC_CTRLB_RESSEL_12BIT:
|
||||
val = val << 4
|
||||
case sam.ADC_CTRLB_RESSEL_16BIT:
|
||||
// Adjust for multiple samples. This is only configured when the
|
||||
// resolution is 16 bits.
|
||||
switch (bus.AVGCTRL.Get() & sam.ADC_AVGCTRL_SAMPLENUM_Msk) >> sam.ADC_AVGCTRL_SAMPLENUM_Pos {
|
||||
case sam.ADC_AVGCTRL_SAMPLENUM_1:
|
||||
val <<= 4
|
||||
case sam.ADC_AVGCTRL_SAMPLENUM_2:
|
||||
val <<= 3
|
||||
case sam.ADC_AVGCTRL_SAMPLENUM_4:
|
||||
val <<= 2
|
||||
case sam.ADC_AVGCTRL_SAMPLENUM_8:
|
||||
val <<= 1
|
||||
default:
|
||||
// These values are all shifted by the hardware so they fit exactly
|
||||
// in a 16-bit integer, so they don't need to be shifted here.
|
||||
}
|
||||
}
|
||||
return val
|
||||
}
|
||||
@@ -1114,7 +1098,7 @@ func (uart *UART) SetBaudRate(br uint32) {
|
||||
}
|
||||
|
||||
// WriteByte writes a byte of data to the UART.
|
||||
func (uart *UART) writeByte(c byte) error {
|
||||
func (uart *UART) WriteByte(c byte) error {
|
||||
// wait until ready to receive
|
||||
for !uart.Bus.INTFLAG.HasBits(sam.SERCOM_USART_INT_INTFLAG_DRE) {
|
||||
}
|
||||
@@ -1122,8 +1106,6 @@ func (uart *UART) writeByte(c byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (uart *UART) flush() {}
|
||||
|
||||
func (uart *UART) handleInterrupt(interrupt.Interrupt) {
|
||||
// should reset IRQ
|
||||
uart.Receive(byte((uart.Bus.DATA.Get() & 0xFF)))
|
||||
@@ -1164,7 +1146,7 @@ const (
|
||||
wireCmdStop = 3
|
||||
)
|
||||
|
||||
const i2cTimeout = 28000 // about 210us
|
||||
const i2cTimeout = 1000
|
||||
|
||||
// Configure is intended to setup the I2C interface.
|
||||
func (i2c *I2C) Configure(config I2CConfig) error {
|
||||
@@ -1508,40 +1490,23 @@ func (spi SPI) Configure(config SPIConfig) error {
|
||||
spi.Bus.CTRLA.ClearBits(sam.SERCOM_SPIM_CTRLA_CPOL)
|
||||
}
|
||||
|
||||
// Set the clock frequency.
|
||||
// There are two clocks we can use GCLK0 (120MHz) and GCLK1 (48MHz).
|
||||
// We can use any even divisor for these clock, which means:
|
||||
// - for GCLK0 we can make 60MHz, 30MHz, 20MHz, 15MHz, 12MHz, 10MHz, etc
|
||||
// - for GCLK1 we can make 24MHz, 12MHz, 8MHz, 6MHz, 4.8MHz, 4MHz, etc
|
||||
// This means that by trying both clocks, we can have a wider selection of
|
||||
// available SPI clock frequencies.
|
||||
|
||||
// Calculate the baudrate if we would use GCLK1 (48MHz), and the resulting
|
||||
// frequency. The baud rate is rounded up, so that the resulting frequency
|
||||
// is rounded down from the maximum value (meaning it will always be smaller
|
||||
// than or equal to config.Frequency).
|
||||
baudRateGCLK1 := (SERCOM_FREQ_REF/2 + config.Frequency - 1) / config.Frequency
|
||||
freqGCLK1 := SERCOM_FREQ_REF / 2 / baudRateGCLK1
|
||||
|
||||
// Same for GCLK0 (120MHz).
|
||||
baudRateGCLK0 := (SERCOM_FREQ_REF_GCLK0/2 + config.Frequency - 1) / config.Frequency
|
||||
freqGCLK0 := SERCOM_FREQ_REF_GCLK0 / 2 / baudRateGCLK0
|
||||
|
||||
// Pick the clock source that is the closest to the maximum baud rate.
|
||||
// Note: there may be reasons to prefer the lower frequency clock (like
|
||||
// power consumption). If that's the case, we might want to always use the
|
||||
// 48MHz clock at low frequencies (below 4MHz or so).
|
||||
if freqGCLK0 > freqGCLK1 && uint32(uint8(baudRateGCLK0-1))+1 == baudRateGCLK0 {
|
||||
// Pick this 120MHz clock if it results in a better frequency after
|
||||
// division, and the baudRate value fits in the BAUD register.
|
||||
// set clock
|
||||
freqRef := uint32(0)
|
||||
if config.Frequency > SERCOM_FREQ_REF/2 {
|
||||
setSERCOMClockGenerator(spi.SERCOM, sam.GCLK_PCHCTRL_GEN_GCLK0)
|
||||
spi.Bus.BAUD.Set(uint8(baudRateGCLK0 - 1))
|
||||
freqRef = uint32(SERCOM_FREQ_REF_GCLK0)
|
||||
} else {
|
||||
// Use the 48MHz clock in other cases.
|
||||
setSERCOMClockGenerator(spi.SERCOM, sam.GCLK_PCHCTRL_GEN_GCLK1)
|
||||
spi.Bus.BAUD.Set(uint8(baudRateGCLK1 - 1))
|
||||
freqRef = uint32(SERCOM_FREQ_REF)
|
||||
}
|
||||
|
||||
// Set synch speed for SPI
|
||||
baudRate := freqRef / (2 * config.Frequency)
|
||||
if baudRate > 0 {
|
||||
baudRate--
|
||||
}
|
||||
spi.Bus.BAUD.Set(uint8(baudRate))
|
||||
|
||||
// Enable SPI port.
|
||||
spi.Bus.CTRLA.SetBits(sam.SERCOM_SPIM_CTRLA_ENABLE)
|
||||
for spi.Bus.SYNCBUSY.HasBits(sam.SERCOM_SPIM_SYNCBUSY_ENABLE) {
|
||||
@@ -2241,12 +2206,12 @@ func (f flashBlockDevice) EraseBlocks(start, len int64) error {
|
||||
|
||||
// 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 {
|
||||
paddingNeeded := f.WriteBlockSize() - (int64(len(p)) % f.WriteBlockSize())
|
||||
if paddingNeeded == 0 {
|
||||
return p
|
||||
}
|
||||
|
||||
padding := bytes.Repeat([]byte{0xff}, int(f.WriteBlockSize()-overflow))
|
||||
padding := bytes.Repeat([]byte{0xff}, int(paddingNeeded))
|
||||
return append(p, padding...)
|
||||
}
|
||||
|
||||
@@ -2299,52 +2264,3 @@ func checkFlashError() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Watchdog provides access to the hardware watchdog available
|
||||
// in the SAMD51.
|
||||
var Watchdog = &watchdogImpl{}
|
||||
|
||||
const (
|
||||
// WatchdogMaxTimeout in milliseconds (16s)
|
||||
WatchdogMaxTimeout = (16384 * 1000) / 1024 // CYC16384/1024kHz
|
||||
)
|
||||
|
||||
type watchdogImpl struct{}
|
||||
|
||||
// Configure the watchdog.
|
||||
//
|
||||
// This method should not be called after the watchdog is started and on
|
||||
// some platforms attempting to reconfigure after starting the watchdog
|
||||
// is explicitly forbidden / will not work.
|
||||
func (wd *watchdogImpl) Configure(config WatchdogConfig) error {
|
||||
// 1.024kHz clock
|
||||
cycles := int((int64(config.TimeoutMillis) * 1024) / 1000)
|
||||
|
||||
// period is expressed as a power-of-two, starting at 8 / 1024ths of a second
|
||||
period := uint8(0)
|
||||
cfgCycles := 8
|
||||
for cfgCycles < cycles {
|
||||
period++
|
||||
cfgCycles <<= 1
|
||||
|
||||
if period >= 0xB {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
sam.WDT.CONFIG.Set(period << sam.WDT_CONFIG_PER_Pos)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Starts the watchdog.
|
||||
func (wd *watchdogImpl) Start() error {
|
||||
sam.WDT.CTRLA.SetBits(sam.WDT_CTRLA_ENABLE)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update the watchdog, indicating that `source` is healthy.
|
||||
func (wd *watchdogImpl) Update() {
|
||||
// 0xA5 = magic value (see datasheet)
|
||||
sam.WDT.CLEAR.Set(0xA5)
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
//go:build attiny1616
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/avr"
|
||||
)
|
||||
|
||||
const (
|
||||
portA Pin = iota * 8
|
||||
portB
|
||||
portC
|
||||
)
|
||||
|
||||
const (
|
||||
PA0 = portA + 0
|
||||
PA1 = portA + 1
|
||||
PA2 = portA + 2
|
||||
PA3 = portA + 3
|
||||
PA4 = portA + 4
|
||||
PA5 = portA + 5
|
||||
PA6 = portA + 6
|
||||
PA7 = portA + 7
|
||||
PB0 = portB + 0
|
||||
PB1 = portB + 1
|
||||
PB2 = portB + 2
|
||||
PB3 = portB + 3
|
||||
PB4 = portB + 4
|
||||
PB5 = portB + 5
|
||||
PB6 = portB + 6
|
||||
PB7 = portB + 7
|
||||
PC0 = portC + 0
|
||||
PC1 = portC + 1
|
||||
PC2 = portC + 2
|
||||
PC3 = portC + 3
|
||||
PC4 = portC + 4
|
||||
PC5 = portC + 5
|
||||
PC6 = portC + 6
|
||||
PC7 = portC + 7
|
||||
)
|
||||
|
||||
// getPortMask returns the PORT peripheral and mask for the pin.
|
||||
func (p Pin) getPortMask() (*avr.PORT_Type, uint8) {
|
||||
switch {
|
||||
case p >= PA0 && p <= PA7: // port A
|
||||
return avr.PORTA, 1 << uint8(p-portA)
|
||||
case p >= PB0 && p <= PB7: // port B
|
||||
return avr.PORTB, 1 << uint8(p-portB)
|
||||
default: // port C
|
||||
return avr.PORTC, 1 << uint8(p-portC)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build avr && !avrtiny
|
||||
//go:build avr
|
||||
|
||||
package machine
|
||||
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
//go:build avrtiny
|
||||
|
||||
package machine
|
||||
|
||||
import (
|
||||
"device/avr"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const deviceName = avr.DEVICE
|
||||
|
||||
const (
|
||||
PinInput PinMode = iota
|
||||
PinInputPullup
|
||||
PinOutput
|
||||
)
|
||||
|
||||
// Configure sets the pin to input or output.
|
||||
func (p Pin) Configure(config PinConfig) {
|
||||
port, mask := p.getPortMask()
|
||||
|
||||
if config.Mode == PinOutput {
|
||||
// set output bit
|
||||
port.DIRSET.Set(mask)
|
||||
|
||||
// Note: the output state (high or low) is as it was before.
|
||||
} else {
|
||||
// Configure the pin as an input.
|
||||
// First set up the configuration that will be used when it is an input.
|
||||
pinctrl := uint8(0)
|
||||
if config.Mode == PinInputPullup {
|
||||
pinctrl |= avr.PORT_PIN0CTRL_PULLUPEN
|
||||
}
|
||||
// Find the PINxCTRL register for this pin.
|
||||
ctrlAddress := (*volatile.Register8)(unsafe.Add(unsafe.Pointer(&port.PIN0CTRL), p%8))
|
||||
ctrlAddress.Set(pinctrl)
|
||||
|
||||
// Configure the pin as input (if it wasn't an input pin before).
|
||||
port.DIRCLR.Set(mask)
|
||||
}
|
||||
}
|
||||
|
||||
// Get returns the current value of a GPIO pin when the pin is configured as an
|
||||
// input or as an output.
|
||||
func (p Pin) Get() bool {
|
||||
port, mask := p.getPortMask()
|
||||
// As noted above, the PINx register is always two registers below the PORTx
|
||||
// register, so we can find it simply by subtracting two from the PORTx
|
||||
// register address.
|
||||
return (port.IN.Get() & mask) > 0
|
||||
}
|
||||
|
||||
// Set changes the value of the GPIO pin. The pin must be configured as output.
|
||||
func (p Pin) Set(high bool) {
|
||||
port, mask := p.getPortMask()
|
||||
if high {
|
||||
port.OUTSET.Set(mask)
|
||||
} else {
|
||||
port.OUTCLR.Set(mask)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
//go:build cortexm
|
||||
|
||||
package machine
|
||||
|
||||
import "device/arm"
|
||||
|
||||
// CPUReset performs a hard system reset.
|
||||
func CPUReset() {
|
||||
arm.SystemReset()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user