mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-27 07:08:42 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ca7b95039d | |||
| 7939c060ce | |||
| dd04f34059 | |||
| f58e75c386 | |||
| b8db79f6a6 |
+31
-143
@@ -28,7 +28,6 @@ commands:
|
||||
qemu-user \
|
||||
gcc-avr \
|
||||
avr-libc
|
||||
sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-8-dev
|
||||
install-node:
|
||||
steps:
|
||||
- run:
|
||||
@@ -38,54 +37,28 @@ commands:
|
||||
sudo tar -C /usr/local -xf node-v10.15.1-linux-x64.tar.xz
|
||||
sudo ln -s /usr/local/node-v10.15.1-linux-x64/bin/node /usr/bin/node
|
||||
rm node-v10.15.1-linux-x64.tar.xz
|
||||
install-chrome:
|
||||
steps:
|
||||
- run:
|
||||
name: "Install Chrome"
|
||||
command: |
|
||||
wget https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
||||
sudo apt install ./google-chrome-stable_current_amd64.deb
|
||||
install-wasmtime:
|
||||
steps:
|
||||
- run:
|
||||
name: "Install wasmtime"
|
||||
command: |
|
||||
curl https://wasmtime.dev/install.sh -sSf | bash
|
||||
sudo ln -s ~/.wasmtime/bin/wasmtime /usr/local/bin/wasmtime
|
||||
install-xtensa-toolchain:
|
||||
parameters:
|
||||
variant:
|
||||
type: string
|
||||
steps:
|
||||
- run:
|
||||
name: "Install Xtensa toolchain"
|
||||
command: |
|
||||
curl -L https://github.com/espressif/crosstool-NG/releases/download/esp-2020r2/xtensa-esp32-elf-gcc8_2_0-esp-2020r2-<<parameters.variant>>.tar.gz -o xtensa-esp32-elf-gcc8_2_0-esp-2020r2-<<parameters.variant>>.tar.gz
|
||||
sudo tar -C /usr/local -xf xtensa-esp32-elf-gcc8_2_0-esp-2020r2-<<parameters.variant>>.tar.gz
|
||||
sudo ln -s /usr/local/xtensa-esp32-elf/bin/xtensa-esp32-elf-ld /usr/local/bin/xtensa-esp32-elf-ld
|
||||
rm xtensa-esp32-elf-gcc8_2_0-esp-2020r2-<<parameters.variant>>.tar.gz
|
||||
llvm-source-linux:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- llvm-source-10-v1
|
||||
- llvm-source-10-v0
|
||||
- run:
|
||||
name: "Fetch LLVM source"
|
||||
command: make llvm-source
|
||||
- save_cache:
|
||||
key: llvm-source-10-v1
|
||||
key: llvm-source-10-v0
|
||||
paths:
|
||||
- llvm-project
|
||||
build-wasi-libc:
|
||||
steps:
|
||||
- restore_cache:
|
||||
keys:
|
||||
- wasi-libc-sysroot-v3
|
||||
- wasi-libc-sysroot-v2
|
||||
- run:
|
||||
name: "Build wasi-libc"
|
||||
command: make wasi-libc
|
||||
- save_cache:
|
||||
key: wasi-libc-sysroot-v3
|
||||
key: wasi-libc-sysroot-v2
|
||||
paths:
|
||||
- lib/wasi-libc/sysroot
|
||||
test-linux:
|
||||
@@ -98,8 +71,6 @@ commands:
|
||||
- apt-dependencies:
|
||||
llvm: "<<parameters.llvm>>"
|
||||
- install-node
|
||||
- install-chrome
|
||||
- install-wasmtime
|
||||
- restore_cache:
|
||||
keys:
|
||||
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
||||
@@ -108,21 +79,20 @@ commands:
|
||||
- run: go install -tags=llvm<<parameters.llvm>> .
|
||||
- restore_cache:
|
||||
keys:
|
||||
- wasi-libc-sysroot-systemclang-v2
|
||||
- wasi-libc-sysroot-systemclang-v1
|
||||
- run: make wasi-libc
|
||||
- save_cache:
|
||||
key: wasi-libc-sysroot-systemclang-v2
|
||||
key: wasi-libc-sysroot-systemclang-v1
|
||||
paths:
|
||||
- lib/wasi-libc/sysroot
|
||||
- run: go test -v -tags=llvm<<parameters.llvm>> ./cgo ./compileopts ./interp ./transform .
|
||||
- run: go test -v -tags=llvm<<parameters.llvm>> ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||
- run: make gen-device -j4
|
||||
- run: make smoketest XTENSA=0
|
||||
- run: make tinygo-test
|
||||
- run: make wasmtest
|
||||
- run: make smoketest
|
||||
- save_cache:
|
||||
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
||||
paths:
|
||||
- ~/.cache/go-build
|
||||
- ~/.cache/tinygo
|
||||
- /go/pkg/mod
|
||||
- run: make fmt-check
|
||||
assert-test-linux:
|
||||
@@ -134,6 +104,7 @@ commands:
|
||||
command: |
|
||||
sudo apt-get install \
|
||||
gcc-arm-linux-gnueabihf \
|
||||
binutils-arm-none-eabi \
|
||||
libc6-dev-armel-cross \
|
||||
gcc-aarch64-linux-gnu \
|
||||
libc6-dev-arm64-cross \
|
||||
@@ -141,11 +112,7 @@ commands:
|
||||
qemu-user \
|
||||
gcc-avr \
|
||||
avr-libc
|
||||
sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-6-dev
|
||||
- install-node
|
||||
- install-wasmtime
|
||||
- install-xtensa-toolchain:
|
||||
variant: "linux-amd64"
|
||||
- restore_cache:
|
||||
keys:
|
||||
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
||||
@@ -153,7 +120,7 @@ commands:
|
||||
- llvm-source-linux
|
||||
- restore_cache:
|
||||
keys:
|
||||
- llvm-build-10-linux-v1-assert
|
||||
- llvm-build-10-linux-v0-assert
|
||||
- run:
|
||||
name: "Build LLVM"
|
||||
command: |
|
||||
@@ -171,7 +138,7 @@ commands:
|
||||
make ASSERT=1 llvm-build
|
||||
fi
|
||||
- save_cache:
|
||||
key: llvm-build-10-linux-v1-assert
|
||||
key: llvm-build-10-linux-v0-assert
|
||||
paths:
|
||||
llvm-build
|
||||
- run: make ASSERT=1
|
||||
@@ -183,6 +150,7 @@ commands:
|
||||
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
||||
paths:
|
||||
- ~/.cache/go-build
|
||||
- ~/.cache/tinygo
|
||||
- /go/pkg/mod
|
||||
- run: make gen-device -j4
|
||||
- run: make smoketest TINYGO=build/tinygo
|
||||
@@ -195,6 +163,7 @@ commands:
|
||||
command: |
|
||||
sudo apt-get install \
|
||||
gcc-arm-linux-gnueabihf \
|
||||
binutils-arm-none-eabi \
|
||||
libc6-dev-armel-cross \
|
||||
gcc-aarch64-linux-gnu \
|
||||
libc6-dev-arm64-cross \
|
||||
@@ -202,11 +171,7 @@ commands:
|
||||
qemu-user \
|
||||
gcc-avr \
|
||||
avr-libc
|
||||
sudo apt-get install --no-install-recommends libc6-dev-i386 lib32gcc-6-dev
|
||||
- install-node
|
||||
- install-wasmtime
|
||||
- install-xtensa-toolchain:
|
||||
variant: "linux-amd64"
|
||||
- restore_cache:
|
||||
keys:
|
||||
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
||||
@@ -214,7 +179,7 @@ commands:
|
||||
- llvm-source-linux
|
||||
- restore_cache:
|
||||
keys:
|
||||
- llvm-build-10-linux-v1
|
||||
- llvm-build-10-linux-v0
|
||||
- run:
|
||||
name: "Build LLVM"
|
||||
command: |
|
||||
@@ -232,32 +197,25 @@ commands:
|
||||
make llvm-build
|
||||
fi
|
||||
- save_cache:
|
||||
key: llvm-build-10-linux-v1
|
||||
key: llvm-build-10-linux-v0
|
||||
paths:
|
||||
llvm-build
|
||||
- build-wasi-libc
|
||||
- run:
|
||||
name: "Test TinyGo"
|
||||
command: make test
|
||||
- run:
|
||||
name: "Install fpm"
|
||||
command: |
|
||||
sudo apt-get install ruby ruby-dev
|
||||
sudo gem install --no-document fpm
|
||||
- run:
|
||||
name: "Build TinyGo release"
|
||||
command: |
|
||||
make release deb -j3
|
||||
make release -j3
|
||||
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
|
||||
cp -p build/release.deb /tmp/tinygo_amd64.deb
|
||||
- store_artifacts:
|
||||
path: /tmp/tinygo.linux-amd64.tar.gz
|
||||
- store_artifacts:
|
||||
path: /tmp/tinygo_amd64.deb
|
||||
- save_cache:
|
||||
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
||||
paths:
|
||||
- ~/.cache/go-build
|
||||
- ~/.cache/tinygo
|
||||
- /go/pkg/mod
|
||||
- run:
|
||||
name: "Extract release tarball"
|
||||
@@ -278,25 +236,23 @@ commands:
|
||||
sudo tar -C /usr/local -xzf go1.14.darwin-amd64.tar.gz
|
||||
ln -s /usr/local/go/bin/go /usr/local/bin/go
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu
|
||||
- install-xtensa-toolchain:
|
||||
variant: "macos"
|
||||
- restore_cache:
|
||||
keys:
|
||||
- go-cache-macos-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
||||
- go-cache-macos-v2-{{ checksum "go.mod" }}
|
||||
- restore_cache:
|
||||
keys:
|
||||
- llvm-source-10-macos-v1
|
||||
- llvm-source-10-macos-v0
|
||||
- run:
|
||||
name: "Fetch LLVM source"
|
||||
command: make llvm-source
|
||||
- save_cache:
|
||||
key: llvm-source-10-macos-v1
|
||||
key: llvm-source-10-macos-v0
|
||||
paths:
|
||||
- llvm-project
|
||||
- restore_cache:
|
||||
keys:
|
||||
- llvm-build-10-macos-v1
|
||||
- llvm-build-10-macos-v0
|
||||
- run:
|
||||
name: "Build LLVM"
|
||||
command: |
|
||||
@@ -308,17 +264,17 @@ commands:
|
||||
make llvm-build
|
||||
fi
|
||||
- save_cache:
|
||||
key: llvm-build-10-macos-v1
|
||||
key: llvm-build-10-macos-v0
|
||||
paths:
|
||||
llvm-build
|
||||
- restore_cache:
|
||||
keys:
|
||||
- wasi-libc-sysroot-macos-v2
|
||||
- wasi-libc-sysroot-macos-v1
|
||||
- run:
|
||||
name: "Build wasi-libc"
|
||||
command: make wasi-libc
|
||||
- save_cache:
|
||||
key: wasi-libc-sysroot-macos-v2
|
||||
key: wasi-libc-sysroot-macos-v1
|
||||
paths:
|
||||
- lib/wasi-libc/sysroot
|
||||
- run:
|
||||
@@ -338,66 +294,19 @@ commands:
|
||||
tar -C /usr/local/opt -xf /tmp/tinygo.darwin-amd64.tar.gz
|
||||
ln -s /usr/local/opt/tinygo/bin/tinygo /usr/local/bin/tinygo
|
||||
tinygo version
|
||||
- run:
|
||||
name: "Download SiFive GNU toolchain"
|
||||
command: |
|
||||
curl -O https://static.dev.sifive.com/dev-tools/riscv64-unknown-elf-gcc-8.2.0-2019.05.3-x86_64-apple-darwin.tar.gz
|
||||
sudo tar -C /usr/local --strip-components=1 -xf riscv64-unknown-elf-gcc-8.2.0-2019.05.3-x86_64-apple-darwin.tar.gz
|
||||
- run: make smoketest AVR=0
|
||||
- save_cache:
|
||||
key: go-cache-macos-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
||||
paths:
|
||||
- ~/.cache/go-build
|
||||
- ~/.cache/tinygo
|
||||
- /go/pkg/mod
|
||||
arch-release:
|
||||
steps:
|
||||
- run:
|
||||
name: Install dependencies
|
||||
command: pacman -Sy --noconfirm openssh git pacman-contrib binutils
|
||||
- run:
|
||||
name: Create TinyGo user
|
||||
command: useradd -m tinygo
|
||||
- run:
|
||||
name: Start SSH Agent
|
||||
user: tinygo
|
||||
command: eval $(ssh-agent -s)
|
||||
- run:
|
||||
name: Add ARCH_RELEASE_SSH_PRIVATE_KEY identity
|
||||
user: tinygo
|
||||
command: echo "${ARCH_RELEASE_SSH_PRIVATE_KEY}" | tr -d '\r' | ssh-add -
|
||||
- run:
|
||||
name: Create SSH directory
|
||||
user: tinygo
|
||||
command: mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
||||
- run:
|
||||
name: Add aur.archlinux.org to known hosts
|
||||
user: tinygo
|
||||
command: ssh-keyscan aur.archlinux.org >> ~/.ssh/known_hosts
|
||||
- run:
|
||||
name: Clone tinygo-bin repo
|
||||
user: tinygo
|
||||
command: git clone ssh://aur@aur.archlinux.org/tinygo-bin.git ~/tinygo-bin
|
||||
- run:
|
||||
name: Update package version
|
||||
user: tinygo
|
||||
command: sed -i -E "s/(pkgver=)(.*)$/\1${CIRCLE_TAG}/" ~/tinygo-bin/PKGBUILD
|
||||
- run:
|
||||
name: Update file checksums
|
||||
user: tinygo
|
||||
command: cd ~/tinygo-bin && updpkgsums
|
||||
- run:
|
||||
name: Update .SRCINFO
|
||||
user: tinygo
|
||||
command: cd ~/tinygo-bin && makepkg --printsrcinfo > .SRCINFO
|
||||
# Commit the update
|
||||
- run:
|
||||
name: Set git commit config
|
||||
user: tinygo
|
||||
command: |
|
||||
git config --global user.email "tinygo-bot@tinygo.org" &&
|
||||
git config --global user.name "TinyGo Release Bot"
|
||||
- run:
|
||||
name: Commit and push changes
|
||||
user: tinygo
|
||||
command: |
|
||||
cd ~/tinygo-bin &&
|
||||
git commit -a -m "Update tinygo-bin to v${CIRCLE_TAG}" &&
|
||||
git push origin master
|
||||
|
||||
|
||||
jobs:
|
||||
test-llvm9-go111:
|
||||
@@ -424,12 +333,6 @@ jobs:
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "10"
|
||||
test-llvm11-go115:
|
||||
docker:
|
||||
- image: circleci/golang:1.15-buster
|
||||
steps:
|
||||
- test-linux:
|
||||
llvm: "11"
|
||||
assert-test-linux:
|
||||
docker:
|
||||
- image: circleci/golang:1.14-stretch
|
||||
@@ -445,11 +348,6 @@ jobs:
|
||||
xcode: "10.1.0"
|
||||
steps:
|
||||
- build-macos
|
||||
arch-release:
|
||||
docker:
|
||||
- image: archlinux:latest
|
||||
steps:
|
||||
- arch-release
|
||||
|
||||
|
||||
|
||||
@@ -461,16 +359,6 @@ workflows:
|
||||
- test-llvm10-go112
|
||||
- test-llvm10-go113
|
||||
- test-llvm10-go114
|
||||
- test-llvm11-go115
|
||||
- build-linux
|
||||
- build-macos
|
||||
- assert-test-linux
|
||||
release:
|
||||
jobs:
|
||||
- arch-release:
|
||||
filters:
|
||||
branches:
|
||||
ignore: /.*/
|
||||
tags:
|
||||
# Runs on every semver release
|
||||
only: /v[0-9]+(\.[0-9]+)*(-.*)*/
|
||||
|
||||
@@ -3,19 +3,14 @@ docs/_build
|
||||
src/device/avr/*.go
|
||||
src/device/avr/*.ld
|
||||
src/device/avr/*.s
|
||||
src/device/esp/*.go
|
||||
src/device/nrf/*.go
|
||||
src/device/nrf/*.s
|
||||
src/device/nxp/*.go
|
||||
src/device/nxp/*.s
|
||||
src/device/sam/*.go
|
||||
src/device/sam/*.s
|
||||
src/device/sifive/*.go
|
||||
src/device/sifive/*.s
|
||||
src/device/stm32/*.go
|
||||
src/device/stm32/*.s
|
||||
src/device/kendryte/*.go
|
||||
src/device/kendryte/*.s
|
||||
vendor
|
||||
llvm-build
|
||||
llvm-project
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
url = https://github.com/avr-rust/avr-mcu.git
|
||||
[submodule "lib/cmsis-svd"]
|
||||
path = lib/cmsis-svd
|
||||
url = https://github.com/tinygo-org/cmsis-svd
|
||||
url = https://github.com/posborne/cmsis-svd
|
||||
[submodule "lib/compiler-rt"]
|
||||
path = lib/compiler-rt
|
||||
url = https://github.com/llvm-mirror/compiler-rt.git
|
||||
|
||||
-12
@@ -10,14 +10,6 @@ This guide describes how to statically link TinyGo against LLVM, libclang and
|
||||
lld so that the binary can be easily moved between systems. It also shows how to
|
||||
build a release tarball that includes this binary and all necessary extra files.
|
||||
|
||||
**Note**: this documentation describes how to build a statically linked release
|
||||
tarball. If you want to develop TinyGo, you will probably want to follow a
|
||||
different guide:
|
||||
|
||||
* [Linux](https://tinygo.org/getting-started/linux/#source-install)
|
||||
* [macOS](https://tinygo.org/getting-started/macos/#source-install)
|
||||
* [Windows](https://tinygo.org/getting-started/windows/#source-install)
|
||||
|
||||
## Dependencies
|
||||
|
||||
LLVM, Clang and LLD are quite light on dependencies, requiring only standard
|
||||
@@ -92,10 +84,6 @@ Now that we have a working static build, it's time to make a release tarball:
|
||||
|
||||
make release
|
||||
|
||||
If you did not clone the repository with the `--recursive` option, you will get errors until you initialize the project submodules:
|
||||
|
||||
git submodule update --init
|
||||
|
||||
The release tarball is stored in build/release.tar.gz, and can be extracted with
|
||||
the following command (for example in ~/lib):
|
||||
|
||||
|
||||
-223
@@ -1,226 +1,3 @@
|
||||
0.16.0
|
||||
---
|
||||
|
||||
* **command-line**
|
||||
- add initial support for LLVM 11
|
||||
- make lib64 clang include path check more robust
|
||||
- `build`: improve support for GOARCH=386 and add tests
|
||||
- `gdb`: add support for qemu-user targets
|
||||
- `test`: support non-host tests
|
||||
- `test`: add support for -c and -o flags
|
||||
- `test`: implement some benchmark stubs
|
||||
* **compiler**
|
||||
- `builder`: improve detection of clang on Fedora
|
||||
- `compiler`: fix floating point comparison bugs
|
||||
- `compiler`: implement negate for complex numbers
|
||||
- `loader`: fix linkname in test binaries
|
||||
- `transform`: add missing return pointer restore for regular coroutine tail
|
||||
calls
|
||||
* **standard library**
|
||||
- `machine`: switch default frequency to 4MHz
|
||||
- `machine`: clarify caller's responsibility in `SetInterrupt`
|
||||
- `os`: add `LookupEnv()` stub
|
||||
- `reflect`: implement `Swapper`
|
||||
- `runtime`: fix UTF-8 decoding
|
||||
- `runtime`: gc: use raw stack access whenever possible
|
||||
- `runtime`: use dedicated printfloat32
|
||||
- `runtime`: allow ranging over a nil map
|
||||
- `runtime`: avoid device/nxp dependency in HardFault handler
|
||||
- `testing`: implement dummy Helper method
|
||||
- `testing`: add Run method
|
||||
* **targets**
|
||||
- `arm64`: add support for SVCall intrinsic
|
||||
- `atsamd51`: avoid panic when configuring SPI with SDI=NoPin
|
||||
- `avr`: properly support the `.rodata` section
|
||||
- `esp8266`: implement `Pin.Get` function
|
||||
- `nintendoswitch`: fix crash when printing long lines (> 120)
|
||||
- `nintendoswitch`: add env parser and removed unused stuff
|
||||
- `nrf`: add I2C error checking
|
||||
- `nrf`: give more flexibility in picking SPI speeds
|
||||
- `nrf`: fix nrf52832 flash size
|
||||
- `stm32f103`: support wakeups from interrupts
|
||||
- `stm32f405`: add SPI support
|
||||
- `stm32f405`: add I2C support
|
||||
- `wasi`: add support for this target
|
||||
- `wasi`: use 'generic' ABI by default
|
||||
- `wasi`: remove --no-threads flag from wasm-ld
|
||||
- `wasm`: add instanceof support for WebAssembly
|
||||
- `wasm`: use fixed length buffer for putchar
|
||||
* **boards**
|
||||
- `d1mini`: add this ESP8266 based board
|
||||
- `esp32`: use board definitions instead of chip names
|
||||
- `qtpy`: add board definition for Adafruit QTPy
|
||||
- `teensy40`: add this board
|
||||
|
||||
0.15.0
|
||||
---
|
||||
|
||||
* **command-line**
|
||||
- add cached GOROOT to info subcommand
|
||||
- embed git-hash in tinygo-dev executable
|
||||
- implement tinygo targets to list usable targets
|
||||
- use simpler file copy instead of file renaming to avoid issues on nrf52840 UF2 bootloaders
|
||||
- use ToSlash() to specify program path
|
||||
- support flashing esp32/esp8266 directly from tinygo
|
||||
- when flashing call PortReset only on other than openocd
|
||||
* **compiler**
|
||||
- `compileopts`: add support for custom binary formats
|
||||
- `compiler`: improve display of goroutine wrappers
|
||||
- `interp`: don't panic in the Store method
|
||||
- `interp`: replace some panics with error messages
|
||||
- `interp`: show error line in first line of the traceback
|
||||
- `loader`: be more robust when creating the cached GOROOT
|
||||
- `loader`: rewrite/refactor much of the code to use go list directly
|
||||
- `loader`: use ioutil.TempDir to create a temporary directory
|
||||
- `stacksize`: deal with DW_CFA_advance_loc1
|
||||
* **standard library**
|
||||
- `runtime`: use waitForEvents when appropriate
|
||||
* **wasm**
|
||||
- `wasm`: Remove --no-threads from wasm-ld calls.
|
||||
- `wasm`: update wasi-libc dependency
|
||||
* **targets**
|
||||
- `arduino-mega2560`: fix flashing on Windows
|
||||
- `arm`: automatically determine stack sizes
|
||||
- `arm64`: make dynamic loader structs and constants private
|
||||
- `avr`: configure emulator in board files
|
||||
- `cortexm`: fix stack size calculation with interrupts
|
||||
- `flash`: add openocd settings to atsamd21 / atsamd51
|
||||
- `flash`: add openocd settings to nrf5
|
||||
- `microbit`: reelboard: flash using OpenOCD when needed
|
||||
- `nintendoswitch`: Add dynamic loader for runtime loading PIE sections
|
||||
- `nintendoswitch`: fix import cycle on dynamic_arm64.go
|
||||
- `nintendoswitch`: Fix invalid memory read / write in print calls
|
||||
- `nintendoswitch`: simplified assembly code
|
||||
- `nintendoswitch`: support outputting .nro files directly
|
||||
* **boards**
|
||||
- `arduino-zero`: Adding support for the Arduino Zero (#1365)
|
||||
- `atsamd2x`: fix BAUD value
|
||||
- `atsamd5x`: fix BAUD value
|
||||
- `bluepill`: Enable stm32's USART2 for the board and map it to UART1 tinygo's device
|
||||
- `device/atsamd51x`: add all remaining bitfield values for PCHCTRLm Mapping
|
||||
- `esp32`: add libgcc ROM functions to linker script
|
||||
- `esp32`: add SPI support
|
||||
- `esp32`: add support for basic GPIO
|
||||
- `esp32`: add support for the Espressif ESP32 chip
|
||||
- `esp32`: configure the I/O matrix for GPIO pins
|
||||
- `esp32`: export machine.PortMask* for bitbanging implementations
|
||||
- `esp8266`: add support for this chip
|
||||
- `machine/atsamd51x,runtime/atsamd51x`: fixes needed for full support for all PWM pins. Also adds some useful constants to clarify peripheral clock usage
|
||||
- `machine/itsybitsy-nrf52840`: add support for Adafruit Itsybitsy nrf52840 (#1243)
|
||||
- `machine/stm32f4`: refactor common code and add new build tag stm32f4 (#1332)
|
||||
- `nrf`: add SoftDevice support for the Circuit Playground Bluefruit
|
||||
- `nrf`: call sd_app_evt_wait when the SoftDevice is enabled
|
||||
- `nrf52840`: add build tags for SoftDevice support
|
||||
- `nrf52840`: use higher priority for USB-CDC code
|
||||
- `runtime/atsamd51x`: use PCHCTRL_GCLK_SERCOMX_SLOW for setting clocks on all SERCOM ports
|
||||
- `stm32f405`: add basic UART handler
|
||||
- `stm32f405`: add STM32F405 machine/runtime, and new board/target feather-stm32f405
|
||||
* **build**
|
||||
- `all`: run test binaries in the correct directory
|
||||
- `build`: Fix arch release job
|
||||
- `ci`: run `tinygo test` for known-working packages
|
||||
- `ci`: set git-fetch-depth to 1
|
||||
- `docker`: fix the problem with the wasm build (#1357)
|
||||
- `Makefile`: check whether submodules have been downloaded in some common cases
|
||||
* **docs**
|
||||
- add ESP32, ESP8266, and Adafruit Feather STM32F405 to list of supported boards
|
||||
|
||||
0.14.1
|
||||
---
|
||||
* **command-line**
|
||||
- support for Go 1.15
|
||||
* **compiler**
|
||||
- loader: work around Windows symlink limitation
|
||||
|
||||
0.14.0
|
||||
---
|
||||
* **command-line**
|
||||
- fix `getDefaultPort()` on non-English Windows locales
|
||||
- compileopts: improve error reporting of unsupported flags
|
||||
- fix test subcommand
|
||||
- use auto-retry to locate MSD for UF2 and HEX flashing
|
||||
- fix touchSerialPortAt1200bps on Windows
|
||||
- support package names with backslashes on Windows
|
||||
* **compiler**
|
||||
- fix a few crashes due to named types
|
||||
- add support for atomic operations
|
||||
- move the channel blocked list onto the stack
|
||||
- fix -gc=none
|
||||
- fix named string to `[]byte` slice conversion
|
||||
- implement func value and builtin defers
|
||||
- add proper parameter names to runtime.initAll, to fix a panic
|
||||
- builder: fix picolibc include path
|
||||
- builder: use newer version of gohex
|
||||
- builder: try to determine stack size information at compile time
|
||||
- builder: remove -opt=0
|
||||
- interp: fix sync/atomic.Value load/store methods
|
||||
- loader: add Go module support
|
||||
- transform: fix debug information in func lowering pass
|
||||
- transform: do not special-case zero or one implementations of a method call
|
||||
- transform: introduce check for method calls on nil interfaces
|
||||
- transform: gc: track 0-index GEPs to fix miscompilation
|
||||
* **cgo**
|
||||
- Add LDFlags support
|
||||
* **standard library**
|
||||
- extend stdlib to allow import of more packages
|
||||
- replace master/slave terminology with appropriate alternatives (MOSI->SDO
|
||||
etc)
|
||||
- `internal/bytealg`: reimplement bytealg in pure Go
|
||||
- `internal/task`: fix nil panic in (*internal/task.Stack).Pop
|
||||
- `os`: add Args and stub it with mock data
|
||||
- `os`: implement virtual filesystem support
|
||||
- `reflect`: add Cap and Len support for map and chan
|
||||
- `runtime`: fix return address in scheduler on RISC-V
|
||||
- `runtime`: avoid recursion in printuint64 function
|
||||
- `runtime`: replace ReadRegister with AsmFull inline assembly
|
||||
- `runtime`: fix compilation errors when using gc.extalloc
|
||||
- `runtime`: add cap and len support for chans
|
||||
- `runtime`: refactor time handling (improving accuracy)
|
||||
- `runtime`: make channels work in interrupts
|
||||
- `runtime/interrupt`: add cross-chip disable/restore interrupt support
|
||||
- `sync`: implement `sync.Cond`
|
||||
- `sync`: add WaitGroup
|
||||
* **targets**
|
||||
- `arm`: allow nesting in DisableInterrupts and EnableInterrupts
|
||||
- `arm`: make FPU configuraton consistent
|
||||
- `arm`: do not mask fault handlers in critical sections
|
||||
- `atmega2560`: fix pin mapping for pins D2, D5 and the L port
|
||||
- `atsamd`: return an error when an incorrect PWM pin is used
|
||||
- `atsamd`: add support for pin change interrupts
|
||||
- `atsamd`: add DAC support
|
||||
- `atsamd21`: add more ADC pins
|
||||
- `atsamd51`: fix ROM / RAM size on atsamd51j20
|
||||
- `atsamd51`: add more pins
|
||||
- `atsamd51`: add more ADC pins
|
||||
- `atsamd51`: add pin change interrupt settings
|
||||
- `atsamd51`: extend pinPadMapping
|
||||
- `arduino-nano33`: use (U)SB flag to ensure that device can be found when
|
||||
not on default port
|
||||
- `arduino-nano33`: remove (d)ebug flag to reduce console noise when flashing
|
||||
- `avr`: use standard pin numbering
|
||||
- `avr`: unify GPIO pin/port code
|
||||
- `avr`: add support for PinInputPullup
|
||||
- `avr`: work around codegen bug in LLVM 10
|
||||
- `avr`: fix target triple
|
||||
- `fe310`: remove extra println left in by mistake
|
||||
- `feather-nrf52840`: add support for the Feather nRF52840
|
||||
- `maixbit`: add board definition and dummy runtime
|
||||
- `nintendoswitch`: Add experimental Nintendo Switch support without CRT
|
||||
- `nrf`: expose the RAM base address
|
||||
- `nrf`: add support for pin change interrupts
|
||||
- `nrf`: add microbit-s110v8 target
|
||||
- `nrf`: fix bug in SPI.Tx
|
||||
- `nrf`: support debugging the PCA10056
|
||||
- `pygamer`: add Adafruit PyGamer suport
|
||||
- `riscv`: fix interrupt configuration bug
|
||||
- `riscv`: disable linker relaxations during gp init
|
||||
- `stm32f4disco`: add new target with ST-Link v2.1 debugger
|
||||
- `teensy36`: add Teensy 3.6 support
|
||||
- `wasm`: fix event handling
|
||||
- `wasm`: add --no-demangle linker option
|
||||
- `wioterminal`: add support for the Seeed Wio Terminal
|
||||
- `xiao`: add support for the Seeed XIAO
|
||||
|
||||
0.13.1
|
||||
---
|
||||
* **standard library**
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ Microcontrollers have lots of peripherals (I2C, SPI, ADC, etc.) and many don't h
|
||||
|
||||
## How to use our Github repository
|
||||
|
||||
The `release` branch of this repo will always have the latest released version of TinyGo. All of the active development work for the next release will take place in the `dev` branch. TinyGo will use semantic versioning and will create a tag/release for each release.
|
||||
The `master` branch of this repo will always have the latest released version of TinyGo. All of the active development work for the next release will take place in the `dev` branch. TinyGo will use semantic versioning and will create a tag/release for each release.
|
||||
|
||||
Here is how to contribute back some code or documentation:
|
||||
|
||||
|
||||
+1
-1
@@ -15,4 +15,4 @@ Ayke van Laethem <aykevanlaethem@gmail.com>
|
||||
Daniel Esteban <conejo@conejo.me>
|
||||
Loon, LLC.
|
||||
Ron Evans <ron@hybridgroup.com>
|
||||
Nia Weiss <niaow1234@gmail.com>
|
||||
Jaden Weiss <jaden@jadendw.dev>
|
||||
|
||||
+6
-6
@@ -1,10 +1,10 @@
|
||||
# TinyGo base stage installs the most recent Go 1.15.x, LLVM 10 and the TinyGo compiler itself.
|
||||
FROM golang:1.15 AS tinygo-base
|
||||
# TinyGo base stage installs Go 1.14, LLVM 10 and the TinyGo compiler itself.
|
||||
FROM golang:1.14 AS tinygo-base
|
||||
|
||||
RUN wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key| apt-key add - && \
|
||||
echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-10 main" >> /etc/apt/sources.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y llvm-10-dev libclang-10-dev lld-10 git
|
||||
apt-get install -y llvm-10-dev libclang-10-dev git
|
||||
|
||||
COPY . /tinygo
|
||||
|
||||
@@ -27,10 +27,10 @@ COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
|
||||
COPY --from=tinygo-base /tinygo/src /tinygo/src
|
||||
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
|
||||
|
||||
RUN cd /tinygo/ && \
|
||||
RUN wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key| apt-key add - && \
|
||||
echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-10 main" >> /etc/apt/sources.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y make clang-10 libllvm10 lld-10 && \
|
||||
make wasi-libc
|
||||
apt-get install -y libllvm10 lld-10
|
||||
|
||||
# tinygo-avr stage installs the needed dependencies to compile TinyGo programs for AVR microcontrollers.
|
||||
FROM tinygo-base AS tinygo-avr
|
||||
|
||||
@@ -9,10 +9,25 @@ CLANG_SRC ?= $(LLVM_PROJECTDIR)/clang
|
||||
LLD_SRC ?= $(LLVM_PROJECTDIR)/lld
|
||||
|
||||
# Try to autodetect LLVM build tools.
|
||||
detect = $(shell command -v $(1) 2> /dev/null && echo $(1))
|
||||
CLANG ?= $(word 1,$(abspath $(call detect,llvm-build/bin/clang))$(call detect,clang-11)$(call detect,clang-10)$(call detect,clang))
|
||||
LLVM_AR ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-ar))$(call detect,llvm-ar-11)$(call detect,llvm-ar-10)$(call detect,llvm-ar))
|
||||
LLVM_NM ?= $(word 1,$(abspath $(call detect,llvm-build/bin/llvm-nm))$(call detect,llvm-nm-11)$(call detect,llvm-nm-10)$(call detect,llvm-nm))
|
||||
ifneq (, $(shell command -v llvm-build/bin/clang 2> /dev/null))
|
||||
CLANG ?= $(abspath llvm-build/bin/clang)
|
||||
else
|
||||
CLANG ?= clang-10
|
||||
endif
|
||||
ifneq (, $(shell command -v llvm-build/bin/llvm-ar 2> /dev/null))
|
||||
LLVM_AR ?= $(abspath llvm-build/bin/llvm-ar)
|
||||
else ifneq (, $(shell command -v llvm-ar-10 2> /dev/null))
|
||||
LLVM_AR ?= llvm-ar-10
|
||||
else
|
||||
LLVM_AR ?= llvm-ar
|
||||
endif
|
||||
ifneq (, $(shell command -v llvm-build/bin/llvm-nm 2> /dev/null))
|
||||
LLVM_NM ?= $(abspath llvm-build/bin/llvm-nm)
|
||||
else ifneq (, $(shell command -v llvm-nm-10 2> /dev/null))
|
||||
LLVM_NM ?= llvm-nm-10
|
||||
else
|
||||
LLVM_NM ?= llvm-nm
|
||||
endif
|
||||
|
||||
# Go binary and GOROOT to select
|
||||
GO ?= go
|
||||
@@ -22,7 +37,7 @@ export GOROOT = $(shell $(GO) env GOROOT)
|
||||
MD5SUM = md5sum
|
||||
|
||||
# tinygo binary for tests
|
||||
TINYGO ?= $(word 1,$(call detect,tinygo)$(call detect,build/tinygo))
|
||||
TINYGO ?= tinygo
|
||||
|
||||
# Use CCACHE for LLVM if possible
|
||||
ifneq (, $(shell command -v ccache 2> /dev/null))
|
||||
@@ -36,7 +51,7 @@ else
|
||||
LLVM_OPTION += '-DLLVM_ENABLE_ASSERTIONS=OFF'
|
||||
endif
|
||||
|
||||
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-nxp gen-device-avr
|
||||
.PHONY: all tinygo test $(LLVM_BUILDDIR) llvm-source clean fmt gen-device gen-device-nrf gen-device-avr
|
||||
|
||||
LLVM_COMPONENTS = all-targets analysis asmparser asmprinter bitreader bitwriter codegen core coroutines coverage debuginfodwarf executionengine frontendopenmp instrumentation interpreter ipo irreader linker lto mc mcjit objcarcopts option profiledata scalaropts support target
|
||||
|
||||
@@ -89,24 +104,23 @@ LLD_LIBS = $(START_GROUP) -llldCOFF -llldCommon -llldCore -llldDriver -llldELF -
|
||||
ifneq ("$(wildcard $(LLVM_BUILDDIR)/bin/llvm-config*)","")
|
||||
CGO_CPPFLAGS=$(shell $(LLVM_BUILDDIR)/bin/llvm-config --cppflags) -I$(abspath $(LLVM_BUILDDIR))/tools/clang/include -I$(abspath $(CLANG_SRC))/include -I$(abspath $(LLD_SRC))/include
|
||||
CGO_CXXFLAGS=-std=c++14
|
||||
CGO_LDFLAGS+=$(LIBCLANG_PATH) -L$(abspath $(LLVM_BUILDDIR)/lib) $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
|
||||
CGO_LDFLAGS+=$(LIBCLANG_PATH) -std=c++14 -L$(abspath $(LLVM_BUILDDIR)/lib) $(CLANG_LIBS) $(LLD_LIBS) $(shell $(LLVM_BUILDDIR)/bin/llvm-config --ldflags --libs --system-libs $(LLVM_COMPONENTS)) -lstdc++ $(CGO_LDFLAGS_EXTRA)
|
||||
endif
|
||||
|
||||
|
||||
clean:
|
||||
@rm -rf build
|
||||
|
||||
FMT_PATHS = ./*.go builder cgo compiler interp ir loader src/device/arm src/examples src/machine src/os src/reflect src/runtime src/sync src/syscall src/internal/reflectlite transform
|
||||
FMT_PATHS = ./*.go builder cgo compiler compiler/testdata interp loader src/device/arm src/examples src/machine src/os src/reflect src/runtime src/sync src/syscall src/internal/reflectlite transform
|
||||
fmt:
|
||||
@gofmt -l -w $(FMT_PATHS)
|
||||
fmt-check:
|
||||
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
|
||||
|
||||
|
||||
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-stm32 gen-device-kendryte gen-device-nxp
|
||||
gen-device: gen-device-avr gen-device-nrf gen-device-sam gen-device-sifive gen-device-stm32
|
||||
|
||||
gen-device-avr:
|
||||
@if [ ! -e lib/avr/README.md ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
|
||||
$(GO) build -o ./build/gen-device-avr ./tools/gen-device-avr/
|
||||
./build/gen-device-avr lib/avr/packs/atmega src/device/avr/
|
||||
./build/gen-device-avr lib/avr/packs/tiny src/device/avr/
|
||||
@@ -115,18 +129,10 @@ gen-device-avr:
|
||||
build/gen-device-svd: ./tools/gen-device-svd/*.go
|
||||
$(GO) build -o $@ ./tools/gen-device-svd/
|
||||
|
||||
gen-device-esp: build/gen-device-svd
|
||||
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Espressif-Community -interrupts=software lib/cmsis-svd/data/Espressif-Community/ src/device/esp/
|
||||
GO111MODULE=off $(GO) fmt ./src/device/esp
|
||||
|
||||
gen-device-nrf: build/gen-device-svd
|
||||
./build/gen-device-svd -source=https://github.com/NordicSemiconductor/nrfx/tree/master/mdk lib/nrfx/mdk/ src/device/nrf/
|
||||
GO111MODULE=off $(GO) fmt ./src/device/nrf
|
||||
|
||||
gen-device-nxp: build/gen-device-svd
|
||||
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/NXP lib/cmsis-svd/data/NXP/ src/device/nxp/
|
||||
GO111MODULE=off $(GO) fmt ./src/device/nxp
|
||||
|
||||
gen-device-sam: build/gen-device-svd
|
||||
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Atmel lib/cmsis-svd/data/Atmel/ src/device/sam/
|
||||
GO111MODULE=off $(GO) fmt ./src/device/sam
|
||||
@@ -135,10 +141,6 @@ gen-device-sifive: build/gen-device-svd
|
||||
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/SiFive-Community -interrupts=software lib/cmsis-svd/data/SiFive-Community/ src/device/sifive/
|
||||
GO111MODULE=off $(GO) fmt ./src/device/sifive
|
||||
|
||||
gen-device-kendryte: build/gen-device-svd
|
||||
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Kendryte-Community -interrupts=software lib/cmsis-svd/data/Kendryte-Community/ src/device/kendryte/
|
||||
GO111MODULE=off $(GO) fmt ./src/device/kendryte
|
||||
|
||||
gen-device-stm32: build/gen-device-svd
|
||||
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/STMicro lib/cmsis-svd/data/STMicro/ src/device/stm32/
|
||||
GO111MODULE=off $(GO) fmt ./src/device/stm32
|
||||
@@ -146,13 +148,13 @@ gen-device-stm32: build/gen-device-svd
|
||||
|
||||
# Get LLVM sources.
|
||||
$(LLVM_PROJECTDIR)/README.md:
|
||||
git clone -b xtensa_release_10.0.1 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
|
||||
git clone -b release/10.x https://github.com/llvm/llvm-project $(LLVM_PROJECTDIR)
|
||||
llvm-source: $(LLVM_PROJECTDIR)/README.md
|
||||
|
||||
# Configure LLVM.
|
||||
TINYGO_SOURCE_DIR=$(shell pwd)
|
||||
$(LLVM_BUILDDIR)/build.ninja: llvm-source
|
||||
mkdir -p $(LLVM_BUILDDIR); cd $(LLVM_BUILDDIR); cmake -G Ninja $(TINYGO_SOURCE_DIR)/$(LLVM_PROJECTDIR)/llvm "-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=AVR;Xtensa" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_LIBEDIT=OFF -DLLVM_ENABLE_Z3_SOLVER=OFF -DLLVM_ENABLE_OCAMLDOC=OFF -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD=OFF $(LLVM_OPTION)
|
||||
mkdir -p $(LLVM_BUILDDIR); cd $(LLVM_BUILDDIR); cmake -G Ninja $(TINYGO_SOURCE_DIR)/$(LLVM_PROJECTDIR)/llvm "-DLLVM_TARGETS_TO_BUILD=X86;ARM;AArch64;RISCV;WebAssembly" "-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=AVR" -DCMAKE_BUILD_TYPE=Release -DLIBCLANG_BUILD_STATIC=ON -DLLVM_ENABLE_TERMINFO=OFF -DLLVM_ENABLE_ZLIB=OFF -DLLVM_ENABLE_PROJECTS="clang;lld" -DLLVM_TOOL_CLANG_TOOLS_EXTRA_BUILD=OFF $(LLVM_OPTION)
|
||||
|
||||
# Build LLVM.
|
||||
$(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja
|
||||
@@ -163,40 +165,24 @@ $(LLVM_BUILDDIR): $(LLVM_BUILDDIR)/build.ninja
|
||||
.PHONY: wasi-libc
|
||||
wasi-libc: lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a
|
||||
lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
|
||||
@if [ ! -e lib/wasi-libc/Makefile ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
|
||||
cd lib/wasi-libc && make -j4 WASM_CC=$(CLANG) WASM_AR=$(LLVM_AR) WASM_NM=$(LLVM_NM)
|
||||
|
||||
|
||||
# Build the Go compiler.
|
||||
tinygo:
|
||||
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " make llvm-source"; echo " make $(LLVM_BUILDDIR)"; exit 1; fi
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X main.gitSha1=`git rev-parse --short HEAD`" .
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -o build/tinygo$(EXE) -tags byollvm .
|
||||
|
||||
test: wasi-libc
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test -v -buildmode exe -tags byollvm ./cgo ./compileopts ./interp ./transform .
|
||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test -v -tags byollvm ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||
|
||||
# Test known-working standard library packages.
|
||||
# TODO: do this in one command, parallelize, and only show failing tests (no
|
||||
# implied -v flag).
|
||||
.PHONY: tinygo-test
|
||||
tinygo-test:
|
||||
$(TINYGO) test container/heap
|
||||
$(TINYGO) test container/list
|
||||
$(TINYGO) test container/ring
|
||||
$(TINYGO) test crypto/des
|
||||
$(TINYGO) test encoding/ascii85
|
||||
$(TINYGO) test encoding/base32
|
||||
$(TINYGO) test encoding/hex
|
||||
$(TINYGO) test hash/fnv
|
||||
$(TINYGO) test hash/crc64
|
||||
$(TINYGO) test math
|
||||
$(TINYGO) test text/scanner
|
||||
$(TINYGO) test unicode/utf8
|
||||
cd tests/tinygotest && tinygo test
|
||||
|
||||
.PHONY: smoketest
|
||||
smoketest:
|
||||
$(TINYGO) version
|
||||
# test all examples (except pwm)
|
||||
# test all examples
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/adc
|
||||
@@ -217,7 +203,7 @@ smoketest:
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=microbit examples/microbit-blink
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/pininterrupt
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/serial
|
||||
@$(MD5SUM) test.hex
|
||||
@@ -228,6 +214,8 @@ smoketest:
|
||||
# test simulated boards on play.tinygo.org
|
||||
$(TINYGO) build -o test.wasm -tags=arduino examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -o test.wasm -tags=hifive1-qemu examples/serial
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -o test.wasm -tags=hifive1b examples/blinky1
|
||||
@$(MD5SUM) test.wasm
|
||||
$(TINYGO) build -o test.wasm -tags=reelboard examples/blinky1
|
||||
@@ -243,8 +231,6 @@ smoketest:
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=microbit examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=microbit-s110v8 examples/echo
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=nrf52840-mdk examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10031 examples/blinky1
|
||||
@@ -271,15 +257,11 @@ smoketest:
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky2
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-stm32f405 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=circuitplay-bluefruit examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/i2s
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=clue-alpha examples/blinky1
|
||||
$(TINYGO) build -size short -o test.hex -target=clue_alpha examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.gba -target=gameboy-advance examples/gba-display
|
||||
@$(MD5SUM) test.gba
|
||||
@@ -309,42 +291,11 @@ smoketest:
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=reelboard-s140v7 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=wioterminal examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pygamer examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=xiao examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/dac
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pyportal examples/dac
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-nrf52840 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=qtpy examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=teensy40 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=teensy36 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
# test pwm
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m4 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pyportal examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
ifneq ($(AVR), 0)
|
||||
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino examples/pwm
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino -scheduler=tasks examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=arduino-nano examples/blinky1
|
||||
@@ -353,33 +304,13 @@ ifneq ($(AVR), 0)
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=digispark -gc=leaking examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
endif
|
||||
ifneq ($(XTENSA), 0)
|
||||
$(TINYGO) build -size short -o test.bin -target=esp32-mini32 examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
$(TINYGO) build -size short -o test.bin -target=nodemcu examples/blinky1
|
||||
@$(MD5SUM) test.bin
|
||||
endif
|
||||
$(TINYGO) build -size short -o test.hex -target=hifive1b examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=hifive1-qemu examples/serial
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=maixbit examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/export
|
||||
$(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/main
|
||||
# test various compiler flags
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -gc=none -scheduler=none examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=1 examples/blinky1
|
||||
@$(MD5SUM) test.hex
|
||||
$(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
|
||||
@$(MD5SUM) test.nro
|
||||
|
||||
wasmtest:
|
||||
$(GO) test ./tests/wasm
|
||||
|
||||
build/release: tinygo gen-device wasi-libc
|
||||
release: tinygo gen-device wasi-libc
|
||||
@mkdir -p build/release/tinygo/bin
|
||||
@mkdir -p build/release/tinygo/lib/clang/include
|
||||
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
|
||||
@@ -414,13 +345,4 @@ build/release: tinygo gen-device wasi-libc
|
||||
./build/tinygo build-library -target=armv6m-none-eabi -o build/release/tinygo/pkg/armv6m-none-eabi/picolibc.a picolibc
|
||||
./build/tinygo build-library -target=armv7m-none-eabi -o build/release/tinygo/pkg/armv7m-none-eabi/picolibc.a picolibc
|
||||
./build/tinygo build-library -target=armv7em-none-eabi -o build/release/tinygo/pkg/armv7em-none-eabi/picolibc.a picolibc
|
||||
|
||||
release: build/release
|
||||
tar -czf build/release.tar.gz -C build/release tinygo
|
||||
|
||||
deb: build/release
|
||||
@mkdir -p build/release-deb/usr/local/bin
|
||||
@mkdir -p build/release-deb/usr/local/lib
|
||||
cp -ar build/release/tinygo build/release-deb/usr/local/lib/tinygo
|
||||
ln -sf ../lib/tinygo/bin/tinygo build/release-deb/usr/local/bin/tinygo
|
||||
fpm -f -s dir -t deb -n tinygo -v $(shell grep "const Version = " goenv/version.go | awk '{print $$NF}') -m '@tinygo-org' --description='TinyGo is a Go compiler for small places.' --license='BSD 3-Clause' --url=https://tinygo.org/ --deb-changelog CHANGELOG.md -p build/release.deb -C ./build/release-deb
|
||||
|
||||
@@ -43,35 +43,27 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
|
||||
|
||||
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
||||
|
||||
The following 44 microcontroller boards are currently supported:
|
||||
The following 32 microcontroller boards are currently supported:
|
||||
|
||||
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||
* [Adafruit CLUE Alpha](https://www.adafruit.com/product/4500)
|
||||
* [Adafruit Feather M0](https://www.adafruit.com/product/2772)
|
||||
* [Adafruit Feather M4](https://www.adafruit.com/product/3857)
|
||||
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
|
||||
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
|
||||
* [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 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 Trinket M0](https://www.adafruit.com/product/3500)
|
||||
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
|
||||
* [Arduino Nano](https://store.arduino.cc/arduino-nano)
|
||||
* [Arduino Nano33 IoT](https://store.arduino.cc/nano-33-iot)
|
||||
* [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3)
|
||||
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
|
||||
* [BBC micro:bit](https://microbit.org/)
|
||||
* [Digispark](http://digistump.com/products/1)
|
||||
* [ESP32](https://www.espressif.com/en/products/socs/esp32)
|
||||
* [ESP8266](https://www.espressif.com/en/products/socs/esp8266)
|
||||
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
|
||||
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
|
||||
* [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)
|
||||
@@ -80,10 +72,6 @@ The following 44 microcontroller boards are currently supported:
|
||||
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
|
||||
* [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/)
|
||||
* [PineTime DevKit](https://www.pine64.org/pinetime/)
|
||||
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
|
||||
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
|
||||
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
|
||||
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
|
||||
* [SiFIve HiFive1](https://www.sifive.com/boards/hifive1)
|
||||
* [ST Micro "Nucleo F103RB"](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html)
|
||||
* [ST Micro STM32F103XX "Bluepill"](http://wiki.stm32duino.com/index.php?title=Blue_Pill)
|
||||
@@ -149,5 +137,3 @@ The original reasoning was: if [Python](https://micropython.org/) can run on mic
|
||||
This project is licensed under the BSD 3-clause license, just like the [Go project](https://golang.org/LICENSE) itself.
|
||||
|
||||
Some code has been copied from the LLVM project and is therefore licensed under [a variant of the Apache 2.0 license](http://releases.llvm.org/10.0.0/LICENSE.TXT). This has been clearly indicated in the header of these files.
|
||||
|
||||
Some code has been copied and/or ported from Paul Stoffregen's Teensy libraries and is therefore licensed under PJRC's license. This has been clearly indicated in the header of these files.
|
||||
|
||||
+10
-15
@@ -1,7 +1,7 @@
|
||||
# Avoid lengthy LLVM rebuilds on each newly pushed branch. Pull requests will
|
||||
# be built anyway.
|
||||
trigger:
|
||||
- release
|
||||
- master
|
||||
- dev
|
||||
|
||||
jobs:
|
||||
@@ -12,27 +12,22 @@ jobs:
|
||||
steps:
|
||||
- task: GoTool@0
|
||||
inputs:
|
||||
version: '1.15'
|
||||
version: '1.14.1'
|
||||
- checkout: self
|
||||
fetchDepth: 1
|
||||
- task: Cache@2
|
||||
- task: CacheBeta@0
|
||||
displayName: Cache LLVM source
|
||||
inputs:
|
||||
key: llvm-source-10-windows-v1
|
||||
key: llvm-source-10-windows-v0
|
||||
path: llvm-project
|
||||
- task: Bash@3
|
||||
displayName: Download LLVM source
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: |
|
||||
make llvm-source
|
||||
# Workaround for bad symlinks:
|
||||
# https://github.com/microsoft/azure-pipelines-tasks/issues/13418
|
||||
rm -f llvm-project/libcxx/test/std/input.output/filesystems/Inputs/static_test_env/bad_symlink
|
||||
script: make llvm-source
|
||||
- task: CacheBeta@0
|
||||
displayName: Cache LLVM build
|
||||
inputs:
|
||||
key: llvm-build-10-windows-v1
|
||||
key: llvm-build-10-windows-v0
|
||||
path: llvm-build
|
||||
- task: Bash@3
|
||||
displayName: Build LLVM
|
||||
@@ -48,11 +43,11 @@ jobs:
|
||||
displayName: Install QEMU
|
||||
inputs:
|
||||
targetType: inline
|
||||
script: choco install qemu --version=2020.06.12
|
||||
script: choco install qemu
|
||||
- task: CacheBeta@0
|
||||
displayName: Cache wasi-libc sysroot
|
||||
inputs:
|
||||
key: wasi-libc-sysroot-v3
|
||||
key: wasi-libc-sysroot-v2
|
||||
path: lib/wasi-libc/sysroot
|
||||
- task: Bash@3
|
||||
displayName: Build wasi-libc
|
||||
@@ -74,7 +69,7 @@ jobs:
|
||||
script: |
|
||||
export PATH="$PATH:./llvm-build/bin:/c/Program Files/qemu"
|
||||
unset GOROOT
|
||||
make build/release -j4
|
||||
make release -j4
|
||||
- publish: $(System.DefaultWorkingDirectory)/build/release/tinygo
|
||||
displayName: Publish zip as artifact
|
||||
artifact: tinygo
|
||||
@@ -85,4 +80,4 @@ jobs:
|
||||
script: |
|
||||
export PATH="$PATH:./llvm-build/bin:/c/Program Files/qemu"
|
||||
unset GOROOT
|
||||
make smoketest TINYGO=build/tinygo AVR=0 XTENSA=0
|
||||
make smoketest TINYGO=build/tinygo AVR=0
|
||||
|
||||
+20
-331
@@ -4,14 +4,11 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -19,40 +16,26 @@ import (
|
||||
"github.com/tinygo-org/tinygo/compiler"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
"github.com/tinygo-org/tinygo/interp"
|
||||
"github.com/tinygo-org/tinygo/stacksize"
|
||||
"github.com/tinygo-org/tinygo/transform"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// BuildResult is the output of a build. This includes the binary itself and
|
||||
// some other metadata that is obtained while building the binary.
|
||||
type BuildResult struct {
|
||||
// A path to the output binary. It will be removed after Build returns, so
|
||||
// if it should be kept it must be copied or moved away.
|
||||
Binary string
|
||||
|
||||
// The directory of the main package. This is useful for testing as the test
|
||||
// binary must be run in the directory of the tested package.
|
||||
MainDir string
|
||||
}
|
||||
|
||||
// Build performs a single package to executable Go build. It takes in a package
|
||||
// name, an output path, and set of compile options and from that it manages the
|
||||
// whole compilation process.
|
||||
//
|
||||
// The error value may be of type *MultiError. Callers will likely want to check
|
||||
// for this case and print such errors individually.
|
||||
func Build(pkgName, outpath string, config *compileopts.Config, action func(BuildResult) error) error {
|
||||
func Build(pkgName, outpath string, config *compileopts.Config, action func(string) error) error {
|
||||
// Compile Go code to IR.
|
||||
machine, err := compiler.NewTargetMachine(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buildOutput, errs := compiler.Compile(pkgName, machine, config)
|
||||
mod, extraFiles, errs := compiler.Compile(pkgName, machine, config)
|
||||
if errs != nil {
|
||||
return newMultiError(errs)
|
||||
}
|
||||
mod := buildOutput.Mod
|
||||
|
||||
if config.Options.PrintIR {
|
||||
fmt.Println("; Generated LLVM IR:")
|
||||
@@ -79,7 +62,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
// keep functions interoperable, pass int64 types as pointers to
|
||||
// stack-allocated values.
|
||||
// Use -wasm-abi=generic to disable this behaviour.
|
||||
if config.WasmAbi() == "js" {
|
||||
if config.Options.WasmAbi == "js" && strings.HasPrefix(config.Triple(), "wasm") {
|
||||
err := transform.ExternalInt64AsPtr(mod)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -90,15 +73,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
// exactly.
|
||||
errs = nil
|
||||
switch config.Options.Opt {
|
||||
/*
|
||||
Currently, turning optimizations off causes compile failures.
|
||||
We rely on the optimizer removing some dead symbols.
|
||||
Avoid providing an option that does not work right now.
|
||||
In the future once everything has been fixed we can re-enable this.
|
||||
|
||||
case "none", "0":
|
||||
errs = transform.Optimize(mod, config, 0, 0, 0) // -O0
|
||||
*/
|
||||
case "none", "0":
|
||||
errs = transform.Optimize(mod, config, 0, 0, 0) // -O0
|
||||
case "1":
|
||||
errs = transform.Optimize(mod, config, 1, 0, 0) // -O1
|
||||
case "2":
|
||||
@@ -117,22 +93,16 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
return errors.New("verification failure after LLVM optimization passes")
|
||||
}
|
||||
|
||||
// LLVM 11 by default tries to emit tail calls (even with the target feature
|
||||
// disabled) unless it is explicitly disabled with a function attribute.
|
||||
// This is a problem, as it tries to emit them and prints an error when it
|
||||
// can't with this feature disabled.
|
||||
// Because as of september 2020 tail calls are not yet widely supported,
|
||||
// they need to be disabled until they are widely supported (at which point
|
||||
// the +tail-call target feautre can be set).
|
||||
if strings.HasPrefix(config.Triple(), "wasm") {
|
||||
transform.DisableTailCalls(mod)
|
||||
}
|
||||
|
||||
// Make sure stack sizes are loaded from a separate section so they can be
|
||||
// modified after linking.
|
||||
var stackSizeLoads []string
|
||||
if config.AutomaticStackSize() {
|
||||
stackSizeLoads = transform.CreateStackSizeLoads(mod, config)
|
||||
// On the AVR, pointers can point either to flash or to RAM, but we don't
|
||||
// know. As a temporary fix, load all global variables in RAM.
|
||||
// In the future, there should be a compiler pass that determines which
|
||||
// pointers are flash and which are in RAM so that pointers can have a
|
||||
// correct address space parameter (address space 1 is for flash).
|
||||
if strings.HasPrefix(config.Triple(), "avr") {
|
||||
transform.NonConstGlobals(mod)
|
||||
if err := llvm.VerifyModule(mod, llvm.PrintMessageAction); err != nil {
|
||||
return errors.New("verification error after making all globals non-constant on AVR")
|
||||
}
|
||||
}
|
||||
|
||||
// Generate output.
|
||||
@@ -208,7 +178,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
}
|
||||
|
||||
// Compile C files in packages.
|
||||
for i, file := range buildOutput.ExtraFiles {
|
||||
for i, file := range extraFiles {
|
||||
outpath := filepath.Join(dir, "pkg"+strconv.Itoa(i)+"-"+filepath.Base(file)+".o")
|
||||
err := runCCompiler(config.Target.Compiler, append(config.CFlags(), "-c", "-o", outpath, file)...)
|
||||
if err != nil {
|
||||
@@ -217,36 +187,12 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
ldflags = append(ldflags, outpath)
|
||||
}
|
||||
|
||||
if len(buildOutput.ExtraLDFlags) > 0 {
|
||||
ldflags = append(ldflags, buildOutput.ExtraLDFlags...)
|
||||
}
|
||||
|
||||
// Link the object files together.
|
||||
err = link(config.Target.Linker, ldflags...)
|
||||
if err != nil {
|
||||
return &commandError{"failed to link", executable, err}
|
||||
}
|
||||
|
||||
var calculatedStacks []string
|
||||
var stackSizes map[string]functionStackSize
|
||||
if config.Options.PrintStacks || config.AutomaticStackSize() {
|
||||
// Try to determine stack sizes at compile time.
|
||||
// Don't do this by default as it usually doesn't work on
|
||||
// unsupported architectures.
|
||||
calculatedStacks, stackSizes, err = determineStackSizes(mod, executable)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if config.AutomaticStackSize() {
|
||||
// Modify the .tinygo_stacksizes section that contains a stack size
|
||||
// for each goroutine.
|
||||
err = modifyStackSizes(executable, stackSizeLoads, stackSizes)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not modify stack sizes: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if config.Options.PrintSizes == "short" || config.Options.PrintSizes == "full" {
|
||||
sizes, err := loadProgramSize(executable)
|
||||
if err != nil {
|
||||
@@ -266,278 +212,21 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
||||
}
|
||||
}
|
||||
|
||||
// Print goroutine stack sizes, as far as possible.
|
||||
if config.Options.PrintStacks {
|
||||
printStacks(calculatedStacks, stackSizes)
|
||||
}
|
||||
|
||||
// Get an Intel .hex file or .bin file from the .elf file.
|
||||
outputBinaryFormat := config.BinaryFormat(outext)
|
||||
switch outputBinaryFormat {
|
||||
case "elf":
|
||||
// do nothing, file is already in ELF format
|
||||
case "hex", "bin":
|
||||
// Extract raw binary, either encoding it as a hex file or as a raw
|
||||
// firmware file.
|
||||
if outext == ".hex" || outext == ".bin" || outext == ".gba" {
|
||||
tmppath = filepath.Join(dir, "main"+outext)
|
||||
err := objcopy(executable, tmppath, outputBinaryFormat)
|
||||
err := objcopy(executable, tmppath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "uf2":
|
||||
} else if outext == ".uf2" {
|
||||
// Get UF2 from the .elf file.
|
||||
tmppath = filepath.Join(dir, "main"+outext)
|
||||
err := convertELFFileToUF2File(executable, tmppath, config.Target.UF2FamilyID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case "esp32", "esp8266":
|
||||
// Special format for the ESP family of chips (parsed by the ROM
|
||||
// bootloader).
|
||||
tmppath = filepath.Join(dir, "main"+outext)
|
||||
err := makeESPFirmareImage(executable, tmppath, outputBinaryFormat)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unknown output binary format: %s", outputBinaryFormat)
|
||||
}
|
||||
return action(BuildResult{
|
||||
Binary: tmppath,
|
||||
MainDir: buildOutput.MainDir,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// functionStackSizes keeps stack size information about a single function
|
||||
// (usually a goroutine).
|
||||
type functionStackSize struct {
|
||||
humanName string
|
||||
stackSize uint64
|
||||
stackSizeType stacksize.SizeType
|
||||
missingStackSize *stacksize.CallNode
|
||||
}
|
||||
|
||||
// determineStackSizes tries to determine the stack sizes of all started
|
||||
// goroutines and of the reset vector. The LLVM module is necessary to find
|
||||
// functions that call a function pointer.
|
||||
func determineStackSizes(mod llvm.Module, executable string) ([]string, map[string]functionStackSize, error) {
|
||||
var callsIndirectFunction []string
|
||||
gowrappers := []string{}
|
||||
gowrapperNames := make(map[string]string)
|
||||
for fn := mod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
|
||||
// Determine which functions call a function pointer.
|
||||
for bb := fn.FirstBasicBlock(); !bb.IsNil(); bb = llvm.NextBasicBlock(bb) {
|
||||
for inst := bb.FirstInstruction(); !inst.IsNil(); inst = llvm.NextInstruction(inst) {
|
||||
if inst.IsACallInst().IsNil() {
|
||||
continue
|
||||
}
|
||||
if callee := inst.CalledValue(); callee.IsAFunction().IsNil() && callee.IsAInlineAsm().IsNil() {
|
||||
callsIndirectFunction = append(callsIndirectFunction, fn.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get a list of "go wrappers", small wrapper functions that decode
|
||||
// parameters when starting a new goroutine.
|
||||
attr := fn.GetStringAttributeAtIndex(-1, "tinygo-gowrapper")
|
||||
if !attr.IsNil() {
|
||||
gowrappers = append(gowrappers, fn.Name())
|
||||
gowrapperNames[fn.Name()] = attr.GetStringValue()
|
||||
}
|
||||
}
|
||||
sort.Strings(gowrappers)
|
||||
|
||||
// Load the ELF binary.
|
||||
f, err := elf.Open(executable)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not load executable for stack size analysis: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
// Determine the frame size of each function (if available) and the callgraph.
|
||||
functions, err := stacksize.CallGraph(f, callsIndirectFunction)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("could not parse executable for stack size analysis: %w", err)
|
||||
}
|
||||
|
||||
// Goroutines need to be started and finished and take up some stack space
|
||||
// that way. This can be measured by measuing the stack size of
|
||||
// tinygo_startTask.
|
||||
if numFuncs := len(functions["tinygo_startTask"]); numFuncs != 1 {
|
||||
return nil, nil, fmt.Errorf("expected exactly one definition of tinygo_startTask, got %d", numFuncs)
|
||||
}
|
||||
baseStackSize, baseStackSizeType, baseStackSizeFailedAt := functions["tinygo_startTask"][0].StackSize()
|
||||
|
||||
sizes := make(map[string]functionStackSize)
|
||||
|
||||
// Add the reset handler function, for convenience. The reset handler runs
|
||||
// startup code and the scheduler. The listed stack size is not the full
|
||||
// stack size: interrupts are not counted.
|
||||
var resetFunction string
|
||||
switch f.Machine {
|
||||
case elf.EM_ARM:
|
||||
// Note: all interrupts happen on this stack so the real size is bigger.
|
||||
resetFunction = "Reset_Handler"
|
||||
}
|
||||
if resetFunction != "" {
|
||||
funcs := functions[resetFunction]
|
||||
if len(funcs) != 1 {
|
||||
return nil, nil, fmt.Errorf("expected exactly one definition of %s in the callgraph, found %d", resetFunction, len(funcs))
|
||||
}
|
||||
stackSize, stackSizeType, missingStackSize := funcs[0].StackSize()
|
||||
sizes[resetFunction] = functionStackSize{
|
||||
stackSize: stackSize,
|
||||
stackSizeType: stackSizeType,
|
||||
missingStackSize: missingStackSize,
|
||||
humanName: resetFunction,
|
||||
}
|
||||
}
|
||||
|
||||
// Add all goroutine wrapper functions.
|
||||
for _, name := range gowrappers {
|
||||
funcs := functions[name]
|
||||
if len(funcs) != 1 {
|
||||
return nil, nil, fmt.Errorf("expected exactly one definition of %s in the callgraph, found %d", name, len(funcs))
|
||||
}
|
||||
humanName := gowrapperNames[name]
|
||||
if humanName == "" {
|
||||
humanName = name // fallback
|
||||
}
|
||||
stackSize, stackSizeType, missingStackSize := funcs[0].StackSize()
|
||||
if baseStackSizeType != stacksize.Bounded {
|
||||
// It was not possible to determine the stack size at compile time
|
||||
// because tinygo_startTask does not have a fixed stack size. This
|
||||
// can happen when using -opt=1.
|
||||
stackSizeType = baseStackSizeType
|
||||
missingStackSize = baseStackSizeFailedAt
|
||||
} else if stackSize < baseStackSize {
|
||||
// This goroutine has a very small stack, but still needs to fit all
|
||||
// registers to start and suspend the goroutine. Otherwise a stack
|
||||
// overflow will occur even before the goroutine is started.
|
||||
stackSize = baseStackSize
|
||||
}
|
||||
sizes[name] = functionStackSize{
|
||||
stackSize: stackSize,
|
||||
stackSizeType: stackSizeType,
|
||||
missingStackSize: missingStackSize,
|
||||
humanName: humanName,
|
||||
}
|
||||
}
|
||||
|
||||
if resetFunction != "" {
|
||||
return append([]string{resetFunction}, gowrappers...), sizes, nil
|
||||
}
|
||||
return gowrappers, sizes, nil
|
||||
}
|
||||
|
||||
// modifyStackSizes modifies the .tinygo_stacksizes section with the updated
|
||||
// stack size information. Before this modification, all stack sizes in the
|
||||
// section assume the default stack size (which is relatively big).
|
||||
func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map[string]functionStackSize) error {
|
||||
fp, err := os.OpenFile(executable, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fp.Close()
|
||||
|
||||
elfFile, err := elf.NewFile(fp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
section := elfFile.Section(".tinygo_stacksizes")
|
||||
if section == nil {
|
||||
return errors.New("could not find .tinygo_stacksizes section")
|
||||
}
|
||||
|
||||
if section.Size != section.FileSize {
|
||||
// Sanity check.
|
||||
return fmt.Errorf("expected .tinygo_stacksizes to have identical size and file size, got %d and %d", section.Size, section.FileSize)
|
||||
}
|
||||
|
||||
// Read all goroutine stack sizes.
|
||||
data := make([]byte, section.Size)
|
||||
_, err = fp.ReadAt(data, int64(section.Offset))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(stackSizeLoads)*4 != len(data) {
|
||||
// Note: while AVR should use 2 byte stack sizes, even 64-bit platforms
|
||||
// should probably stick to 4 byte stack sizes as a larger than 4GB
|
||||
// stack doesn't make much sense.
|
||||
return errors.New("expected 4 byte stack sizes")
|
||||
}
|
||||
|
||||
// Modify goroutine stack sizes with a compile-time known worst case stack
|
||||
// size.
|
||||
for i, name := range stackSizeLoads {
|
||||
fn, ok := stackSizes[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("could not find symbol %s in ELF file", name)
|
||||
}
|
||||
if fn.stackSizeType == stacksize.Bounded {
|
||||
stackSize := uint32(fn.stackSize)
|
||||
|
||||
// Adding 4 for the stack canary. Even though the size may be
|
||||
// automatically determined, stack overflow checking is still
|
||||
// important as the stack size cannot be determined for all
|
||||
// goroutines.
|
||||
stackSize += 4
|
||||
|
||||
// Add stack size used by interrupts.
|
||||
switch elfFile.Machine {
|
||||
case elf.EM_ARM:
|
||||
// On Cortex-M (assumed here), this stack size is 8 words or 32
|
||||
// bytes. This is only to store the registers that the interrupt
|
||||
// may modify, the interrupt will switch to the interrupt stack
|
||||
// (MSP).
|
||||
// Some background:
|
||||
// https://interrupt.memfault.com/blog/cortex-m-rtos-context-switching
|
||||
stackSize += 32
|
||||
}
|
||||
|
||||
// Finally write the stack size to the binary.
|
||||
binary.LittleEndian.PutUint32(data[i*4:], stackSize)
|
||||
}
|
||||
}
|
||||
|
||||
// Write back the modified stack sizes.
|
||||
_, err = fp.WriteAt(data, int64(section.Offset))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// printStacks prints the maximum stack depth for functions that are started as
|
||||
// goroutines. Stack sizes cannot always be determined statically, in particular
|
||||
// recursive functions and functions that call interface methods or function
|
||||
// pointers may have an unknown stack depth (depending on what the optimizer
|
||||
// manages to optimize away).
|
||||
//
|
||||
// It might print something like the following:
|
||||
//
|
||||
// function stack usage (in bytes)
|
||||
// Reset_Handler 316
|
||||
// examples/blinky2.led1 92
|
||||
// runtime.run$1 300
|
||||
func printStacks(calculatedStacks []string, stackSizes map[string]functionStackSize) {
|
||||
// Print the sizes of all stacks.
|
||||
fmt.Printf("%-32s %s\n", "function", "stack usage (in bytes)")
|
||||
for _, name := range calculatedStacks {
|
||||
fn := stackSizes[name]
|
||||
switch fn.stackSizeType {
|
||||
case stacksize.Bounded:
|
||||
fmt.Printf("%-32s %d\n", fn.humanName, fn.stackSize)
|
||||
case stacksize.Unknown:
|
||||
fmt.Printf("%-32s unknown, %s does not have stack frame information\n", fn.humanName, fn.missingStackSize)
|
||||
case stacksize.Recursive:
|
||||
fmt.Printf("%-32s recursive, %s may call itself\n", fn.humanName, fn.missingStackSize)
|
||||
case stacksize.IndirectCall:
|
||||
fmt.Printf("%-32s unknown, %s calls a function pointer\n", fn.humanName, fn.missingStackSize)
|
||||
}
|
||||
return action(tmppath)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -21,12 +21,12 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
||||
if goroot == "" {
|
||||
return nil, errors.New("cannot locate $GOROOT, please set it manually")
|
||||
}
|
||||
major, minor, err := goenv.GetGorootVersion(goroot)
|
||||
major, minor, err := getGorootVersion(goroot)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
|
||||
}
|
||||
if major != 1 || minor < 11 || minor > 15 {
|
||||
return nil, fmt.Errorf("requires go version 1.11 through 1.15, got go%d.%d", major, minor)
|
||||
if major != 1 || minor < 11 || minor > 14 {
|
||||
return nil, fmt.Errorf("requires go version 1.11, 1.12, 1.13, or 1.14, got go%d.%d", major, minor)
|
||||
}
|
||||
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
||||
return &compileopts.Config{
|
||||
|
||||
+66
-28
@@ -1,16 +1,71 @@
|
||||
package builder
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// getGorootVersion returns the major and minor version for a given GOROOT path.
|
||||
// If the goroot cannot be determined, (0, 0) is returned.
|
||||
func getGorootVersion(goroot string) (major, minor int, err error) {
|
||||
s, err := GorootVersionString(goroot)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
if s == "" || s[:2] != "go" {
|
||||
return 0, 0, errors.New("could not parse Go version: version does not start with 'go' prefix")
|
||||
}
|
||||
|
||||
parts := strings.Split(s[2:], ".")
|
||||
if len(parts) < 2 {
|
||||
return 0, 0, errors.New("could not parse Go version: version has less than two parts")
|
||||
}
|
||||
|
||||
// Ignore the errors, we don't really handle errors here anyway.
|
||||
var trailing string
|
||||
n, err := fmt.Sscanf(s, "go%d.%d%s", &major, &minor, &trailing)
|
||||
if n == 2 && err == io.EOF {
|
||||
// Means there were no trailing characters (i.e., not an alpha/beta)
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("failed to parse version: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GorootVersionString returns the version string as reported by the Go
|
||||
// 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 := ioutil.ReadFile(filepath.Join(
|
||||
goroot, "src", "runtime", "internal", "sys", "zversion.go")); err == nil {
|
||||
|
||||
r := regexp.MustCompile("const TheVersion = `(.*)`")
|
||||
matches := r.FindSubmatch(data)
|
||||
if len(matches) != 2 {
|
||||
return "", errors.New("Invalid go version output:\n" + string(data))
|
||||
}
|
||||
|
||||
return string(matches[1]), nil
|
||||
|
||||
} else if data, err := ioutil.ReadFile(filepath.Join(goroot, "VERSION")); err == nil {
|
||||
return string(data), nil
|
||||
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
// getClangHeaderPath returns the path to the built-in Clang headers. It tries
|
||||
// multiple locations, which should make it find the directory when installed in
|
||||
// various ways.
|
||||
@@ -29,7 +84,6 @@ func getClangHeaderPath(TINYGOROOT string) string {
|
||||
|
||||
// It looks like we are built with a system-installed LLVM. Do a last
|
||||
// attempt: try to use Clang headers relative to the clang binary.
|
||||
llvmMajor := strings.Split(llvm.Version, ".")[0]
|
||||
for _, cmdName := range commands["clang"] {
|
||||
binpath, err := exec.LookPath(cmdName)
|
||||
if err == nil {
|
||||
@@ -44,38 +98,22 @@ func getClangHeaderPath(TINYGOROOT string) string {
|
||||
// Example executable:
|
||||
// /usr/lib/llvm-9/bin/clang
|
||||
// Example include path:
|
||||
// /usr/lib/llvm-9/lib64/clang/9.0.1/include/
|
||||
llvmRoot := filepath.Dir(filepath.Dir(binpath))
|
||||
clangVersionRoot := filepath.Join(llvmRoot, "lib64", "clang")
|
||||
dirs64, err64 := ioutil.ReadDir(clangVersionRoot)
|
||||
// Example include path:
|
||||
// /usr/lib/llvm-9/lib/clang/9.0.1/include/
|
||||
clangVersionRoot = filepath.Join(llvmRoot, "lib", "clang")
|
||||
dirs32, err32 := ioutil.ReadDir(clangVersionRoot)
|
||||
if err64 != nil && err32 != nil {
|
||||
llvmRoot := filepath.Dir(filepath.Dir(binpath))
|
||||
clangVersionRoot := filepath.Join(llvmRoot, "lib", "clang")
|
||||
dirs, err := ioutil.ReadDir(clangVersionRoot)
|
||||
if err != nil {
|
||||
// Unexpected.
|
||||
continue
|
||||
}
|
||||
dirnames := make([]string, len(dirs64)+len(dirs32))
|
||||
dirCount := 0
|
||||
for _, d := range dirs32 {
|
||||
name := d.Name()
|
||||
if name == llvmMajor || strings.HasPrefix(name, llvmMajor+".") {
|
||||
dirnames[dirCount] = filepath.Join(llvmRoot, "lib", "clang", name)
|
||||
dirCount++
|
||||
}
|
||||
}
|
||||
for _, d := range dirs64 {
|
||||
name := d.Name()
|
||||
if name == llvmMajor || strings.HasPrefix(name, llvmMajor+".") {
|
||||
dirnames[dirCount] = filepath.Join(llvmRoot, "lib64", "clang", name)
|
||||
dirCount++
|
||||
}
|
||||
dirnames := make([]string, len(dirs))
|
||||
for i, d := range dirs {
|
||||
dirnames[i] = d.Name()
|
||||
}
|
||||
sort.Strings(dirnames)
|
||||
// Check for the highest version first.
|
||||
for i := dirCount - 1; i >= 0; i-- {
|
||||
path := filepath.Join(dirnames[i], "include")
|
||||
for i := len(dirnames) - 1; i >= 0; i-- {
|
||||
path := filepath.Join(clangVersionRoot, dirnames[i], "include")
|
||||
_, err := os.Stat(filepath.Join(path, "stdint.h"))
|
||||
if err == nil {
|
||||
return path
|
||||
|
||||
-153
@@ -1,153 +0,0 @@
|
||||
package builder
|
||||
|
||||
// This file implements support for writing ESP image files. These image files
|
||||
// are read by the ROM bootloader so have to be in a particular format.
|
||||
//
|
||||
// In the future, it may be necessary to implement support for other image
|
||||
// formats, such as the ESP8266 image formats (again, used by the ROM bootloader
|
||||
// to load the firmware).
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"debug/elf"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"sort"
|
||||
)
|
||||
|
||||
type espImageSegment struct {
|
||||
addr uint32
|
||||
data []byte
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
// The following documentation has been used:
|
||||
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
|
||||
// https://github.com/espressif/esp-idf/blob/8fbb63c2a701c22ccf4ce249f43aded73e134a34/components/bootloader_support/include/esp_image_format.h#L58
|
||||
// https://github.com/espressif/esptool/blob/master/esptool.py
|
||||
func makeESPFirmareImage(infile, outfile, format string) error {
|
||||
inf, err := elf.Open(infile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer inf.Close()
|
||||
|
||||
// Load all segments to be written to the image. These are actually ELF
|
||||
// sections, not true ELF segments (similar to how esptool does it).
|
||||
var segments []*espImageSegment
|
||||
for _, section := range inf.Sections {
|
||||
if section.Type != elf.SHT_PROGBITS || section.Size == 0 || section.Flags&elf.SHF_ALLOC == 0 {
|
||||
continue
|
||||
}
|
||||
data, err := section.Data()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read section data: %w", err)
|
||||
}
|
||||
for len(data)%4 != 0 {
|
||||
// Align segment to 4 bytes.
|
||||
data = append(data, 0)
|
||||
}
|
||||
if uint64(uint32(section.Addr)) != section.Addr {
|
||||
return fmt.Errorf("section address too big: 0x%x", section.Addr)
|
||||
}
|
||||
segments = append(segments, &espImageSegment{
|
||||
addr: uint32(section.Addr),
|
||||
data: data,
|
||||
})
|
||||
}
|
||||
|
||||
// Sort the segments by address. This is what esptool does too.
|
||||
sort.SliceStable(segments, func(i, j int) bool { return segments[i].addr < segments[j].addr })
|
||||
|
||||
// Calculate checksum over the segment data. This is used in the image
|
||||
// footer.
|
||||
checksum := uint8(0xef)
|
||||
for _, segment := range segments {
|
||||
for _, b := range segment.data {
|
||||
checksum ^= b
|
||||
}
|
||||
}
|
||||
|
||||
// Write first to an in-memory buffer, primarily so that we can easily
|
||||
// calculate a hash over the entire image.
|
||||
// An added benefit is that we don't need to check for errors all the time.
|
||||
outf := &bytes.Buffer{}
|
||||
|
||||
// Image header.
|
||||
switch format {
|
||||
case "esp32":
|
||||
// Header format:
|
||||
// https://github.com/espressif/esp-idf/blob/8fbb63c2/components/bootloader_support/include/esp_image_format.h#L58
|
||||
binary.Write(outf, binary.LittleEndian, struct {
|
||||
magic uint8
|
||||
segment_count uint8
|
||||
spi_mode uint8
|
||||
spi_speed_size uint8
|
||||
entry_addr uint32
|
||||
wp_pin uint8
|
||||
spi_pin_drv [3]uint8
|
||||
reserved [11]uint8
|
||||
hash_appended bool
|
||||
}{
|
||||
magic: 0xE9,
|
||||
segment_count: byte(len(segments)),
|
||||
spi_mode: 0, // irrelevant, replaced by esptool when flashing
|
||||
spi_speed_size: 0, // spi_speed, spi_size: replaced by esptool when flashing
|
||||
entry_addr: uint32(inf.Entry),
|
||||
wp_pin: 0xEE, // disable WP pin
|
||||
hash_appended: true, // add a SHA256 hash
|
||||
})
|
||||
case "esp8266":
|
||||
// Header format:
|
||||
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format
|
||||
// Basically a truncated version of the ESP32 header.
|
||||
binary.Write(outf, binary.LittleEndian, struct {
|
||||
magic uint8
|
||||
segment_count uint8
|
||||
spi_mode uint8
|
||||
spi_speed_size uint8
|
||||
entry_addr uint32
|
||||
}{
|
||||
magic: 0xE9,
|
||||
segment_count: byte(len(segments)),
|
||||
spi_mode: 0, // irrelevant, replaced by esptool when flashing
|
||||
spi_speed_size: 0x20, // spi_speed, spi_size: replaced by esptool when flashing
|
||||
entry_addr: uint32(inf.Entry),
|
||||
})
|
||||
default:
|
||||
return fmt.Errorf("builder: unknown binary format %#v, expected esp32 or esp8266", format)
|
||||
}
|
||||
|
||||
// Write all segments to the image.
|
||||
// https://github.com/espressif/esptool/wiki/Firmware-Image-Format#segment
|
||||
for _, segment := range segments {
|
||||
binary.Write(outf, binary.LittleEndian, struct {
|
||||
addr uint32
|
||||
length uint32
|
||||
}{
|
||||
addr: segment.addr,
|
||||
length: uint32(len(segment.data)),
|
||||
})
|
||||
outf.Write(segment.data)
|
||||
}
|
||||
|
||||
// Footer, including checksum.
|
||||
// The entire image size must be a multiple of 16, so pad the image to one
|
||||
// byte less than that before writing the checksum.
|
||||
outf.Write(make([]byte, 15-outf.Len()%16))
|
||||
outf.WriteByte(checksum)
|
||||
|
||||
if format == "esp32" {
|
||||
// SHA256 hash (to protect against image corruption, not for security).
|
||||
hash := sha256.Sum256(outf.Bytes())
|
||||
outf.Write(hash[:])
|
||||
}
|
||||
|
||||
// Write the image to the output file.
|
||||
return ioutil.WriteFile(outfile, outf.Bytes(), 0666)
|
||||
}
|
||||
+1
-4
@@ -69,14 +69,11 @@ func (l *Library) Load(target string) (path string, err error) {
|
||||
// Precalculate the flags to the compiler invocation.
|
||||
args := append(l.cflags(), "-c", "-Oz", "-g", "-ffunction-sections", "-fdata-sections", "-Wno-macro-redefined", "--target="+target, "-fdebug-prefix-map="+dir+"="+remapDir)
|
||||
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
||||
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft")
|
||||
args = append(args, "-fshort-enums", "-fomit-frame-pointer")
|
||||
}
|
||||
if strings.HasPrefix(target, "riscv32-") {
|
||||
args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128")
|
||||
}
|
||||
if strings.HasPrefix(target, "riscv64-") {
|
||||
args = append(args, "-march=rv64gc", "-mabi=lp64")
|
||||
}
|
||||
|
||||
// Compile all sources.
|
||||
var objs []string
|
||||
|
||||
+17
-27
@@ -4,15 +4,12 @@ import (
|
||||
"debug/elf"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/marcinbor85/gohex"
|
||||
)
|
||||
|
||||
// maxPadBytes is the maximum allowed bytes to be padded in a rom extraction
|
||||
// this value is currently defined by Nintendo Switch Page Alignment (4096 bytes)
|
||||
const maxPadBytes = 4095
|
||||
|
||||
// objcopyError is an error returned by functions that act like objcopy.
|
||||
type objcopyError struct {
|
||||
Op string
|
||||
@@ -61,7 +58,7 @@ func extractROM(path string) (uint64, []byte, error) {
|
||||
|
||||
progs := make(progSlice, 0, 2)
|
||||
for _, prog := range f.Progs {
|
||||
if prog.Type != elf.PT_LOAD || prog.Filesz == 0 || prog.Off == 0 {
|
||||
if prog.Type != elf.PT_LOAD || prog.Filesz == 0 {
|
||||
continue
|
||||
}
|
||||
progs = append(progs, prog)
|
||||
@@ -73,19 +70,8 @@ func extractROM(path string) (uint64, []byte, error) {
|
||||
|
||||
var rom []byte
|
||||
for _, prog := range progs {
|
||||
romEnd := progs[0].Paddr + uint64(len(rom))
|
||||
if prog.Paddr > romEnd && prog.Paddr < romEnd+16 {
|
||||
// Sometimes, the linker seems to insert a bit of padding between
|
||||
// segments. Simply zero-fill these parts.
|
||||
rom = append(rom, make([]byte, prog.Paddr-romEnd)...)
|
||||
}
|
||||
if prog.Paddr != progs[0].Paddr+uint64(len(rom)) {
|
||||
diff := prog.Paddr - (progs[0].Paddr + uint64(len(rom)))
|
||||
if diff > maxPadBytes {
|
||||
return 0, nil, objcopyError{"ROM segments are non-contiguous: " + path, nil}
|
||||
}
|
||||
// Pad the difference
|
||||
rom = append(rom, make([]byte, diff)...)
|
||||
return 0, nil, objcopyError{"ROM segments are non-contiguous: " + path, nil}
|
||||
}
|
||||
data, err := ioutil.ReadAll(prog.Open())
|
||||
if err != nil {
|
||||
@@ -107,7 +93,7 @@ func extractROM(path string) (uint64, []byte, error) {
|
||||
|
||||
// objcopy converts an ELF file to a different (simpler) output file format:
|
||||
// .bin or .hex. It extracts only the .text section.
|
||||
func objcopy(infile, outfile, binaryFormat string) error {
|
||||
func objcopy(infile, outfile string) error {
|
||||
f, err := os.OpenFile(outfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -121,20 +107,24 @@ func objcopy(infile, outfile, binaryFormat string) error {
|
||||
}
|
||||
|
||||
// Write to the file, in the correct format.
|
||||
switch binaryFormat {
|
||||
case "hex":
|
||||
// Intel hex file, includes the firmware start address.
|
||||
switch filepath.Ext(outfile) {
|
||||
case ".gba":
|
||||
// The address is not stored in a .gba file.
|
||||
_, err := f.Write(data)
|
||||
return err
|
||||
case ".bin":
|
||||
// The address is not stored in a .bin file (therefore you
|
||||
// should use .hex files in most cases).
|
||||
_, err := f.Write(data)
|
||||
return err
|
||||
case ".hex":
|
||||
mem := gohex.NewMemory()
|
||||
err := mem.AddBinary(uint32(addr), data)
|
||||
if err != nil {
|
||||
return objcopyError{"failed to create .hex file", err}
|
||||
}
|
||||
return mem.DumpIntelHex(f, 16)
|
||||
case "bin":
|
||||
// The start address is not stored in raw firmware files (therefore you
|
||||
// should use .hex files in most cases).
|
||||
_, err := f.Write(data)
|
||||
return err
|
||||
mem.DumpIntelHex(f, 16) // TODO: handle error
|
||||
return nil
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
|
||||
+3
-17
@@ -41,7 +41,6 @@ type cgoPackage struct {
|
||||
elaboratedTypes map[string]*elaboratedTypeInfo
|
||||
enums map[string]enumInfo
|
||||
anonStructNum int
|
||||
ldflags []string
|
||||
}
|
||||
|
||||
// constantInfo stores some information about a CGo constant found by libclang
|
||||
@@ -157,7 +156,7 @@ typedef unsigned long long _Cgo_ulonglong;
|
||||
// newly created *ast.File that should be added to the list of to-be-parsed
|
||||
// files. If there is one or more error, it returns these in the []error slice
|
||||
// but still modifies the AST.
|
||||
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string) (*ast.File, []string, []error) {
|
||||
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string) (*ast.File, []error) {
|
||||
p := &cgoPackage{
|
||||
dir: dir,
|
||||
fset: fset,
|
||||
@@ -184,7 +183,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||
// Find the absolute path for this package.
|
||||
packagePath, err := filepath.Abs(fset.File(files[0].Pos()).Name())
|
||||
if err != nil {
|
||||
return nil, nil, []error{
|
||||
return nil, []error{
|
||||
scanner.Error{
|
||||
Pos: fset.Position(files[0].Pos()),
|
||||
Msg: "cgo: cannot find absolute path: " + err.Error(), // TODO: wrap this error
|
||||
@@ -360,19 +359,6 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||
}
|
||||
makePathsAbsolute(flags, packagePath)
|
||||
cflags = append(cflags, flags...)
|
||||
case "LDFLAGS":
|
||||
flags, err := shlex.Split(value)
|
||||
if err != nil {
|
||||
// TODO: find the exact location where the error happened.
|
||||
p.addErrorAfter(comment.Slash, comment.Text[:lineStart+colon+1], "failed to parse flags in #cgo line: "+err.Error())
|
||||
continue
|
||||
}
|
||||
if err := checkLinkerFlags(name, flags); err != nil {
|
||||
p.addErrorAfter(comment.Slash, comment.Text[:lineStart+colon+1], err.Error())
|
||||
continue
|
||||
}
|
||||
makePathsAbsolute(flags, packagePath)
|
||||
p.ldflags = append(p.ldflags, flags...)
|
||||
default:
|
||||
startPos := strings.LastIndex(line[4:colon], name) + 4
|
||||
p.addErrorAfter(comment.Slash, comment.Text[:lineStart+startPos], "invalid #cgo line: "+name)
|
||||
@@ -426,7 +412,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
||||
// Print the newly generated in-memory AST, for debugging.
|
||||
//ast.Print(fset, p.generated)
|
||||
|
||||
return p.generated, p.ldflags, p.errors
|
||||
return p.generated, p.errors
|
||||
}
|
||||
|
||||
// makePathsAbsolute converts some common path compiler flags (-I, -L) from
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ func TestCGo(t *testing.T) {
|
||||
}
|
||||
|
||||
// Process the AST with CGo.
|
||||
cgoAST, _, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags)
|
||||
cgoAST, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags)
|
||||
|
||||
// Check the AST for type errors.
|
||||
var typecheckErrors []error
|
||||
|
||||
+3
-3
@@ -246,9 +246,9 @@ func tinygo_clang_globals_visitor(c, parent C.GoCXCursor, client_data C.CXClient
|
||||
}
|
||||
value := source[len(name):]
|
||||
// Try to convert this #define into a Go constant expression.
|
||||
expr, scannerError := parseConst(pos+token.Pos(len(name)), p.fset, value)
|
||||
if scannerError != nil {
|
||||
p.errors = append(p.errors, *scannerError)
|
||||
expr, err := parseConst(pos+token.Pos(len(name)), p.fset, value)
|
||||
if err != nil {
|
||||
p.errors = append(p.errors, err)
|
||||
}
|
||||
if expr != nil {
|
||||
// Parsing was successful.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// +build !byollvm
|
||||
// +build !llvm9,!llvm11
|
||||
// +build !llvm9
|
||||
|
||||
package cgo
|
||||
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
// +build !byollvm
|
||||
// +build llvm11
|
||||
|
||||
package cgo
|
||||
|
||||
/*
|
||||
#cgo linux CFLAGS: -I/usr/lib/llvm-11/include
|
||||
#cgo darwin CFLAGS: -I/usr/local/opt/llvm@11/include
|
||||
#cgo freebsd CFLAGS: -I/usr/local/llvm11/include
|
||||
#cgo linux LDFLAGS: -L/usr/lib/llvm-11/lib -lclang
|
||||
#cgo darwin LDFLAGS: -L/usr/local/opt/llvm@11/lib -lclang -lffi
|
||||
#cgo freebsd LDFLAGS: -L/usr/local/llvm11/lib -lclang
|
||||
*/
|
||||
import "C"
|
||||
Vendored
-7
@@ -21,13 +21,6 @@ package main
|
||||
#if defined(NOTDEFINED)
|
||||
#warning flag must not be defined
|
||||
#endif
|
||||
|
||||
// Check Compiler flags
|
||||
#cgo LDFLAGS: -lc
|
||||
|
||||
// This flag is not valid ldflags
|
||||
#cgo LDFLAGS: -does-not-exists
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
|
||||
Vendored
-1
@@ -1,7 +1,6 @@
|
||||
// CGo errors:
|
||||
// testdata/flags.go:5:7: invalid #cgo line: NOFLAGS
|
||||
// testdata/flags.go:8:13: invalid flag: -fdoes-not-exist
|
||||
// testdata/flags.go:29:14: invalid flag: -does-not-exists
|
||||
|
||||
package main
|
||||
|
||||
|
||||
+5
-71
@@ -118,19 +118,19 @@ func (c *Config) NeedsStackObjects() bool {
|
||||
switch c.GC() {
|
||||
case "conservative", "extalloc":
|
||||
for _, tag := range c.BuildTags() {
|
||||
if tag == "wasm" {
|
||||
return true
|
||||
if tag == "baremetal" {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Scheduler returns the scheduler implementation. Valid values are "none",
|
||||
//"coroutines" and "tasks".
|
||||
// Scheduler returns the scheduler implementation. Valid values are "coroutines"
|
||||
// and "tasks".
|
||||
func (c *Config) Scheduler() string {
|
||||
if c.Options.Scheduler != "" {
|
||||
return c.Options.Scheduler
|
||||
@@ -164,16 +164,6 @@ func (c *Config) PanicStrategy() string {
|
||||
return c.Options.PanicStrategy
|
||||
}
|
||||
|
||||
// AutomaticStackSize returns whether goroutine stack sizes should be determined
|
||||
// automatically at compile time, if possible. If it is false, no attempt is
|
||||
// made.
|
||||
func (c *Config) AutomaticStackSize() bool {
|
||||
if c.Target.AutoStackSize != nil && c.Scheduler() == "tasks" {
|
||||
return *c.Target.AutoStackSize
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo
|
||||
// preprocessing.
|
||||
func (c *Config) CFlags() []string {
|
||||
@@ -186,9 +176,6 @@ func (c *Config) CFlags() []string {
|
||||
cflags = append(cflags, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include"))
|
||||
cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include"))
|
||||
}
|
||||
if c.Debug() {
|
||||
cflags = append(cflags, "-g")
|
||||
}
|
||||
return cflags
|
||||
}
|
||||
|
||||
@@ -239,31 +226,6 @@ func (c *Config) Debug() bool {
|
||||
return c.Options.Debug
|
||||
}
|
||||
|
||||
// BinaryFormat returns an appropriate binary format, based on the file
|
||||
// extension and the configured binary format in the target JSON file.
|
||||
func (c *Config) BinaryFormat(ext string) string {
|
||||
switch ext {
|
||||
case ".bin", ".gba", ".nro":
|
||||
// The simplest format possible: dump everything in a raw binary file.
|
||||
if c.Target.BinaryFormat != "" {
|
||||
return c.Target.BinaryFormat
|
||||
}
|
||||
return "bin"
|
||||
case ".hex":
|
||||
// Similar to bin, but includes the start address and is thus usually a
|
||||
// better format.
|
||||
return "hex"
|
||||
case ".uf2":
|
||||
// Special purpose firmware format, mainly used on Adafruit boards.
|
||||
// More information:
|
||||
// https://github.com/Microsoft/uf2
|
||||
return "uf2"
|
||||
default:
|
||||
// Use the ELF format for unrecognized file formats.
|
||||
return "elf"
|
||||
}
|
||||
}
|
||||
|
||||
// Programmer returns the flash method and OpenOCD interface name given a
|
||||
// particular configuration. It may either be all configured in the target JSON
|
||||
// file or be modified using the -programmmer command-line option.
|
||||
@@ -310,34 +272,6 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
|
||||
return args, nil
|
||||
}
|
||||
|
||||
// CodeModel returns the code model used on this platform.
|
||||
func (c *Config) CodeModel() string {
|
||||
if c.Target.CodeModel != "" {
|
||||
return c.Target.CodeModel
|
||||
}
|
||||
|
||||
return "default"
|
||||
}
|
||||
|
||||
// RelocationModel returns the relocation model in use on this platform. Valid
|
||||
// values are "static", "pic", "dynamicnopic".
|
||||
func (c *Config) RelocationModel() string {
|
||||
if c.Target.RelocationModel != "" {
|
||||
return c.Target.RelocationModel
|
||||
}
|
||||
|
||||
return "static"
|
||||
}
|
||||
|
||||
// WasmAbi returns the WASM ABI which is specified in the target JSON file, and
|
||||
// the value is overridden by `-wasm-abi` flag if it is provided
|
||||
func (c *Config) WasmAbi() string {
|
||||
if c.Options.WasmAbi != "" {
|
||||
return c.Options.WasmAbi
|
||||
}
|
||||
return c.Target.WasmAbi
|
||||
}
|
||||
|
||||
type TestConfig struct {
|
||||
CompileTestBinary bool
|
||||
// TODO: Filter the test functions to run, include verbose flag, etc
|
||||
|
||||
@@ -1,17 +1,5 @@
|
||||
package compileopts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
validGCOptions = []string{"none", "leaking", "extalloc", "conservative"}
|
||||
validSchedulerOptions = []string{"none", "tasks", "coroutines"}
|
||||
validPrintSizeOptions = []string{"none", "short", "full"}
|
||||
validPanicStrategyOptions = []string{"print", "trap"}
|
||||
)
|
||||
|
||||
// Options contains extra options to give to the compiler. These options are
|
||||
// usually passed from the command line.
|
||||
type Options struct {
|
||||
@@ -25,7 +13,6 @@ type Options struct {
|
||||
VerifyIR bool
|
||||
Debug bool
|
||||
PrintSizes string
|
||||
PrintStacks bool
|
||||
CFlags []string
|
||||
LDFlags []string
|
||||
Tags string
|
||||
@@ -34,53 +21,3 @@ type Options struct {
|
||||
TestConfig TestConfig
|
||||
Programmer string
|
||||
}
|
||||
|
||||
// Verify performs a validation on the given options, raising an error if options are not valid.
|
||||
func (o *Options) Verify() error {
|
||||
if o.GC != "" {
|
||||
valid := isInArray(validGCOptions, o.GC)
|
||||
if !valid {
|
||||
return fmt.Errorf(`invalid gc option '%s': valid values are %s`,
|
||||
o.GC,
|
||||
strings.Join(validGCOptions, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
if o.Scheduler != "" {
|
||||
valid := isInArray(validSchedulerOptions, o.Scheduler)
|
||||
if !valid {
|
||||
return fmt.Errorf(`invalid scheduler option '%s': valid values are %s`,
|
||||
o.Scheduler,
|
||||
strings.Join(validSchedulerOptions, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
if o.PrintSizes != "" {
|
||||
valid := isInArray(validPrintSizeOptions, o.PrintSizes)
|
||||
if !valid {
|
||||
return fmt.Errorf(`invalid size option '%s': valid values are %s`,
|
||||
o.PrintSizes,
|
||||
strings.Join(validPrintSizeOptions, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
if o.PanicStrategy != "" {
|
||||
valid := isInArray(validPanicStrategyOptions, o.PanicStrategy)
|
||||
if !valid {
|
||||
return fmt.Errorf(`invalid panic option '%s': valid values are %s`,
|
||||
o.PanicStrategy,
|
||||
strings.Join(validPanicStrategyOptions, ", "))
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isInArray(arr []string, item string) bool {
|
||||
for _, i := range arr {
|
||||
if i == item {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
package compileopts_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
)
|
||||
|
||||
func TestVerifyOptions(t *testing.T) {
|
||||
|
||||
expectedGCError := errors.New(`invalid gc option 'incorrect': valid values are none, leaking, extalloc, conservative`)
|
||||
expectedSchedulerError := errors.New(`invalid scheduler option 'incorrect': valid values are none, tasks, coroutines`)
|
||||
expectedPrintSizeError := errors.New(`invalid size option 'incorrect': valid values are none, short, full`)
|
||||
expectedPanicStrategyError := errors.New(`invalid panic option 'incorrect': valid values are print, trap`)
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
opts compileopts.Options
|
||||
expectedError error
|
||||
}{
|
||||
{
|
||||
name: "OptionsEmpty",
|
||||
opts: compileopts.Options{},
|
||||
},
|
||||
{
|
||||
name: "InvalidGCOption",
|
||||
opts: compileopts.Options{
|
||||
GC: "incorrect",
|
||||
},
|
||||
expectedError: expectedGCError,
|
||||
},
|
||||
{
|
||||
name: "GCOptionNone",
|
||||
opts: compileopts.Options{
|
||||
GC: "none",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GCOptionLeaking",
|
||||
opts: compileopts.Options{
|
||||
GC: "leaking",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GCOptionExtalloc",
|
||||
opts: compileopts.Options{
|
||||
GC: "extalloc",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "GCOptionConservative",
|
||||
opts: compileopts.Options{
|
||||
GC: "conservative",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "InvalidSchedulerOption",
|
||||
opts: compileopts.Options{
|
||||
Scheduler: "incorrect",
|
||||
},
|
||||
expectedError: expectedSchedulerError,
|
||||
},
|
||||
{
|
||||
name: "SchedulerOptionNone",
|
||||
opts: compileopts.Options{
|
||||
Scheduler: "none",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SchedulerOptionTasks",
|
||||
opts: compileopts.Options{
|
||||
Scheduler: "tasks",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "SchedulerOptionCoroutines",
|
||||
opts: compileopts.Options{
|
||||
Scheduler: "coroutines",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "InvalidPrintSizeOption",
|
||||
opts: compileopts.Options{
|
||||
PrintSizes: "incorrect",
|
||||
},
|
||||
expectedError: expectedPrintSizeError,
|
||||
},
|
||||
{
|
||||
name: "PrintSizeOptionNone",
|
||||
opts: compileopts.Options{
|
||||
PrintSizes: "none",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PrintSizeOptionShort",
|
||||
opts: compileopts.Options{
|
||||
PrintSizes: "short",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PrintSizeOptionFull",
|
||||
opts: compileopts.Options{
|
||||
PrintSizes: "full",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "InvalidPanicOption",
|
||||
opts: compileopts.Options{
|
||||
PanicStrategy: "incorrect",
|
||||
},
|
||||
expectedError: expectedPanicStrategyError,
|
||||
},
|
||||
{
|
||||
name: "PanicOptionPrint",
|
||||
opts: compileopts.Options{
|
||||
PanicStrategy: "print",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PanicOptionTrap",
|
||||
opts: compileopts.Options{
|
||||
PanicStrategy: "trap",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := tc.opts.Verify()
|
||||
if tc.expectedError != err {
|
||||
if tc.expectedError.Error() != err.Error() {
|
||||
t.Errorf("expected %v, got %v", tc.expectedError, err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+96
-67
@@ -8,7 +8,6 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
@@ -34,13 +33,11 @@ type TargetSpec struct {
|
||||
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"`
|
||||
Emulator []string `json:"emulator" override:"copy"` // inherited Emulator must not be append
|
||||
Emulator []string `json:"emulator"`
|
||||
FlashCommand string `json:"flash-command"`
|
||||
GDB string `json:"gdb"`
|
||||
PortReset string `json:"flash-1200-bps-reset"`
|
||||
@@ -48,56 +45,90 @@ type TargetSpec struct {
|
||||
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"`
|
||||
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.
|
||||
func (spec *TargetSpec) overrideProperties(child *TargetSpec) {
|
||||
specType := reflect.TypeOf(spec).Elem()
|
||||
specValue := reflect.ValueOf(spec).Elem()
|
||||
childValue := reflect.ValueOf(child).Elem()
|
||||
|
||||
for i := 0; i < specType.NumField(); i++ {
|
||||
field := specType.Field(i)
|
||||
src := childValue.Field(i)
|
||||
dst := specValue.Field(i)
|
||||
|
||||
switch kind := field.Type.Kind(); kind {
|
||||
case reflect.String: // for strings, just copy the field of child to spec if not empty
|
||||
if src.Len() > 0 {
|
||||
dst.Set(src)
|
||||
}
|
||||
case reflect.Uint, reflect.Uint32, reflect.Uint64: // for Uint, copy if not zero
|
||||
if src.Uint() != 0 {
|
||||
dst.Set(src)
|
||||
}
|
||||
case reflect.Ptr: // for pointers, copy if not nil
|
||||
if !src.IsNil() {
|
||||
dst.Set(src)
|
||||
}
|
||||
case reflect.Slice: // for slices...
|
||||
if src.Len() > 0 { // ... if not empty ...
|
||||
switch tag := field.Tag.Get("override"); tag {
|
||||
case "copy":
|
||||
// copy the field of child to spec
|
||||
dst.Set(src)
|
||||
case "append", "":
|
||||
// or append the field of child to spec
|
||||
dst.Set(reflect.AppendSlice(src, dst))
|
||||
default:
|
||||
panic("override mode must be 'copy' or 'append' (default). I don't know how to '" + tag + "'.")
|
||||
}
|
||||
}
|
||||
default:
|
||||
panic("unknown field type : " + kind.String())
|
||||
}
|
||||
// copyProperties copies all properties that are set in spec2 into itself.
|
||||
func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) {
|
||||
// TODO: simplify this using reflection? Inherits and BuildTags are special
|
||||
// cases, but the rest can simply be copied if set.
|
||||
spec.Inherits = append(spec.Inherits, spec2.Inherits...)
|
||||
if spec2.Triple != "" {
|
||||
spec.Triple = spec2.Triple
|
||||
}
|
||||
if spec2.CPU != "" {
|
||||
spec.CPU = spec2.CPU
|
||||
}
|
||||
spec.Features = append(spec.Features, spec2.Features...)
|
||||
if spec2.GOOS != "" {
|
||||
spec.GOOS = spec2.GOOS
|
||||
}
|
||||
if spec2.GOARCH != "" {
|
||||
spec.GOARCH = spec2.GOARCH
|
||||
}
|
||||
spec.BuildTags = append(spec.BuildTags, spec2.BuildTags...)
|
||||
if spec2.GC != "" {
|
||||
spec.GC = spec2.GC
|
||||
}
|
||||
if spec2.Scheduler != "" {
|
||||
spec.Scheduler = spec2.Scheduler
|
||||
}
|
||||
if spec2.Compiler != "" {
|
||||
spec.Compiler = spec2.Compiler
|
||||
}
|
||||
if spec2.Linker != "" {
|
||||
spec.Linker = spec2.Linker
|
||||
}
|
||||
if spec2.RTLib != "" {
|
||||
spec.RTLib = spec2.RTLib
|
||||
}
|
||||
if spec2.Libc != "" {
|
||||
spec.Libc = spec2.Libc
|
||||
}
|
||||
spec.CFlags = append(spec.CFlags, spec2.CFlags...)
|
||||
spec.LDFlags = append(spec.LDFlags, spec2.LDFlags...)
|
||||
if spec2.LinkerScript != "" {
|
||||
spec.LinkerScript = spec2.LinkerScript
|
||||
}
|
||||
spec.ExtraFiles = append(spec.ExtraFiles, spec2.ExtraFiles...)
|
||||
if len(spec2.Emulator) != 0 {
|
||||
spec.Emulator = spec2.Emulator
|
||||
}
|
||||
if spec2.FlashCommand != "" {
|
||||
spec.FlashCommand = spec2.FlashCommand
|
||||
}
|
||||
if spec2.GDB != "" {
|
||||
spec.GDB = spec2.GDB
|
||||
}
|
||||
if spec2.PortReset != "" {
|
||||
spec.PortReset = spec2.PortReset
|
||||
}
|
||||
if spec2.FlashMethod != "" {
|
||||
spec.FlashMethod = spec2.FlashMethod
|
||||
}
|
||||
if spec2.FlashVolume != "" {
|
||||
spec.FlashVolume = spec2.FlashVolume
|
||||
}
|
||||
if spec2.FlashFilename != "" {
|
||||
spec.FlashFilename = spec2.FlashFilename
|
||||
}
|
||||
if spec2.UF2FamilyID != "" {
|
||||
spec.UF2FamilyID = spec2.UF2FamilyID
|
||||
}
|
||||
if spec2.OpenOCDInterface != "" {
|
||||
spec.OpenOCDInterface = spec2.OpenOCDInterface
|
||||
}
|
||||
if spec2.OpenOCDTarget != "" {
|
||||
spec.OpenOCDTarget = spec2.OpenOCDTarget
|
||||
}
|
||||
if spec2.OpenOCDTransport != "" {
|
||||
spec.OpenOCDTransport = spec2.OpenOCDTransport
|
||||
}
|
||||
if spec2.JLinkDevice != "" {
|
||||
spec.JLinkDevice = spec2.JLinkDevice
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,11 +177,11 @@ func (spec *TargetSpec) resolveInherits() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newSpec.overrideProperties(subtarget)
|
||||
newSpec.copyProperties(subtarget)
|
||||
}
|
||||
|
||||
// When all properties are loaded, make sure they are properly inherited.
|
||||
newSpec.overrideProperties(spec)
|
||||
newSpec.copyProperties(spec)
|
||||
*spec = *newSpec
|
||||
|
||||
return nil
|
||||
@@ -216,7 +247,6 @@ func LoadTarget(target string) (*TargetSpec, error) {
|
||||
}
|
||||
goarch := map[string]string{ // map from LLVM arch to Go arch
|
||||
"i386": "386",
|
||||
"i686": "386",
|
||||
"x86_64": "amd64",
|
||||
"aarch64": "arm64",
|
||||
"armv7": "arm",
|
||||
@@ -232,40 +262,39 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
// No target spec available. Use the default one, useful on most systems
|
||||
// with a regular OS.
|
||||
spec := TargetSpec{
|
||||
Triple: triple,
|
||||
GOOS: goos,
|
||||
GOARCH: goarch,
|
||||
BuildTags: []string{goos, goarch},
|
||||
Compiler: "clang",
|
||||
Linker: "cc",
|
||||
CFlags: []string{"--target=" + triple},
|
||||
GDB: "gdb",
|
||||
PortReset: "false",
|
||||
Triple: triple,
|
||||
GOOS: goos,
|
||||
GOARCH: goarch,
|
||||
BuildTags: []string{goos, goarch},
|
||||
Compiler: "clang",
|
||||
Linker: "cc",
|
||||
CFlags: []string{"--target=" + triple},
|
||||
GDB: "gdb",
|
||||
PortReset: "false",
|
||||
FlashMethod: "native",
|
||||
}
|
||||
if goos == "darwin" {
|
||||
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
|
||||
} else {
|
||||
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
|
||||
}
|
||||
if goarch != "wasm" {
|
||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/gc_"+goarch+".S")
|
||||
}
|
||||
if goarch != runtime.GOARCH {
|
||||
// Some educated guesses as to how to invoke helper programs.
|
||||
spec.GDB = "gdb-multiarch"
|
||||
if goarch == "arm" && goos == "linux" {
|
||||
spec.CFlags = append(spec.CFlags, "--sysroot=/usr/arm-linux-gnueabihf")
|
||||
spec.Linker = "arm-linux-gnueabihf-gcc"
|
||||
spec.GDB = "arm-linux-gnueabihf-gdb"
|
||||
spec.Emulator = []string{"qemu-arm", "-L", "/usr/arm-linux-gnueabihf"}
|
||||
}
|
||||
if goarch == "arm64" && goos == "linux" {
|
||||
spec.CFlags = append(spec.CFlags, "--sysroot=/usr/aarch64-linux-gnu")
|
||||
spec.Linker = "aarch64-linux-gnu-gcc"
|
||||
spec.GDB = "aarch64-linux-gnu-gdb"
|
||||
spec.Emulator = []string{"qemu-aarch64", "-L", "/usr/aarch64-linux-gnu"}
|
||||
}
|
||||
if goarch == "386" && runtime.GOARCH == "amd64" {
|
||||
spec.CFlags = append(spec.CFlags, "-m32")
|
||||
spec.LDFlags = append(spec.LDFlags, "-m32")
|
||||
if goarch == "386" {
|
||||
spec.CFlags = []string{"-m32"}
|
||||
spec.LDFlags = []string{"-m32"}
|
||||
}
|
||||
}
|
||||
return &spec, nil
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package compileopts
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
import "testing"
|
||||
|
||||
func TestLoadTarget(t *testing.T) {
|
||||
_, err := LoadTarget("arduino")
|
||||
@@ -20,67 +17,3 @@ func TestLoadTarget(t *testing.T) {
|
||||
t.Error("LoadTarget failed for wrong reason:", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOverrideProperties(t *testing.T) {
|
||||
baseAutoStackSize := true
|
||||
base := &TargetSpec{
|
||||
GOOS: "baseGoos",
|
||||
CPU: "baseCpu",
|
||||
Features: []string{"bf1", "bf2"},
|
||||
BuildTags: []string{"bt1", "bt2"},
|
||||
Emulator: []string{"be1", "be2"},
|
||||
DefaultStackSize: 42,
|
||||
AutoStackSize: &baseAutoStackSize,
|
||||
}
|
||||
childAutoStackSize := false
|
||||
child := &TargetSpec{
|
||||
GOOS: "",
|
||||
CPU: "chlidCpu",
|
||||
Features: []string{"cf1", "cf2"},
|
||||
Emulator: []string{"ce1", "ce2"},
|
||||
AutoStackSize: &childAutoStackSize,
|
||||
DefaultStackSize: 64,
|
||||
}
|
||||
|
||||
base.overrideProperties(child)
|
||||
|
||||
if base.GOOS != "baseGoos" {
|
||||
t.Errorf("Overriding failed : got %v", base.GOOS)
|
||||
}
|
||||
if base.CPU != "chlidCpu" {
|
||||
t.Errorf("Overriding failed : got %v", base.CPU)
|
||||
}
|
||||
if !reflect.DeepEqual(base.Features, []string{"cf1", "cf2", "bf1", "bf2"}) {
|
||||
t.Errorf("Overriding failed : got %v", base.Features)
|
||||
}
|
||||
if !reflect.DeepEqual(base.BuildTags, []string{"bt1", "bt2"}) {
|
||||
t.Errorf("Overriding failed : got %v", base.BuildTags)
|
||||
}
|
||||
if !reflect.DeepEqual(base.Emulator, []string{"ce1", "ce2"}) {
|
||||
t.Errorf("Overriding failed : got %v", base.Emulator)
|
||||
}
|
||||
if *base.AutoStackSize != false {
|
||||
t.Errorf("Overriding failed : got %v", base.AutoStackSize)
|
||||
}
|
||||
if base.DefaultStackSize != 64 {
|
||||
t.Errorf("Overriding failed : got %v", base.DefaultStackSize)
|
||||
}
|
||||
|
||||
baseAutoStackSize = true
|
||||
base = &TargetSpec{
|
||||
AutoStackSize: &baseAutoStackSize,
|
||||
DefaultStackSize: 42,
|
||||
}
|
||||
child = &TargetSpec{
|
||||
AutoStackSize: nil,
|
||||
DefaultStackSize: 0,
|
||||
}
|
||||
base.overrideProperties(child)
|
||||
if *base.AutoStackSize != true {
|
||||
t.Errorf("Overriding failed : got %v", base.AutoStackSize)
|
||||
}
|
||||
if base.DefaultStackSize != 42 {
|
||||
t.Errorf("Overriding failed : got %v", base.DefaultStackSize)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+6
-6
@@ -16,7 +16,7 @@ import (
|
||||
// slice. This is required by the Go language spec: an index out of bounds must
|
||||
// cause a panic.
|
||||
func (b *builder) createLookupBoundsCheck(arrayLen, index llvm.Value, indexType types.Type) {
|
||||
if b.fn.IsNoBounds() {
|
||||
if b.info.nobounds {
|
||||
// The //go:nobounds pragma was added to the function to avoid bounds
|
||||
// checking.
|
||||
return
|
||||
@@ -48,7 +48,7 @@ func (b *builder) createLookupBoundsCheck(arrayLen, index llvm.Value, indexType
|
||||
// biggest possible slice capacity, 'low' means len and 'high' means cap. The
|
||||
// logic is the same in both cases.
|
||||
func (b *builder) createSliceBoundsCheck(capacity, low, high, max llvm.Value, lowType, highType, maxType *types.Basic) {
|
||||
if b.fn.IsNoBounds() {
|
||||
if b.info.nobounds {
|
||||
// The //go:nobounds pragma was added to the function to avoid bounds
|
||||
// checking.
|
||||
return
|
||||
@@ -104,7 +104,7 @@ func (b *builder) createSliceBoundsCheck(capacity, low, high, max llvm.Value, lo
|
||||
// createChanBoundsCheck creates a bounds check before creating a new channel to
|
||||
// check that the value is not too big for runtime.chanMake.
|
||||
func (b *builder) createChanBoundsCheck(elementSize uint64, bufSize llvm.Value, bufSizeType *types.Basic, pos token.Pos) {
|
||||
if b.fn.IsNoBounds() {
|
||||
if b.info.nobounds {
|
||||
// The //go:nobounds pragma was added to the function to avoid bounds
|
||||
// checking.
|
||||
return
|
||||
@@ -189,7 +189,7 @@ func (b *builder) createNilCheck(inst ssa.Value, ptr llvm.Value, blockPrefix str
|
||||
// createNegativeShiftCheck creates an assertion that panics if the given shift value is negative.
|
||||
// This function assumes that the shift value is signed.
|
||||
func (b *builder) createNegativeShiftCheck(shift llvm.Value) {
|
||||
if b.fn.IsNoBounds() {
|
||||
if b.info.nobounds {
|
||||
// Function disabled bounds checking - skip shift check.
|
||||
return
|
||||
}
|
||||
@@ -212,8 +212,8 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
|
||||
}
|
||||
}
|
||||
|
||||
faultBlock := b.ctx.AddBasicBlock(b.fn.LLVMFn, blockPrefix+".throw")
|
||||
nextBlock := b.ctx.AddBasicBlock(b.fn.LLVMFn, blockPrefix+".next")
|
||||
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
|
||||
nextBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".next")
|
||||
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
|
||||
|
||||
// Now branch to the out-of-bounds or the regular block.
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// createAtomicOp lowers an atomic library call by lowering it as an LLVM atomic
|
||||
// operation. It returns the result of the operation and true if the call could
|
||||
// be lowered inline, and false otherwise.
|
||||
func (b *builder) createAtomicOp(call *ssa.CallCommon) (llvm.Value, bool) {
|
||||
name := call.Value.(*ssa.Function).Name()
|
||||
switch name {
|
||||
case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
|
||||
ptr := b.getValue(call.Args[0])
|
||||
val := b.getValue(call.Args[1])
|
||||
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpAdd, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
|
||||
// Return the new value, not the original value returned by atomicrmw.
|
||||
return b.CreateAdd(oldVal, val, ""), true
|
||||
case "SwapInt32", "SwapInt64", "SwapUint32", "SwapUint64", "SwapUintptr", "SwapPointer":
|
||||
ptr := b.getValue(call.Args[0])
|
||||
val := b.getValue(call.Args[1])
|
||||
isPointer := val.Type().TypeKind() == llvm.PointerTypeKind
|
||||
if isPointer {
|
||||
// atomicrmw only supports integers, so cast to an integer.
|
||||
val = b.CreatePtrToInt(val, b.uintptrType, "")
|
||||
ptr = b.CreateBitCast(ptr, llvm.PointerType(val.Type(), 0), "")
|
||||
}
|
||||
oldVal := b.CreateAtomicRMW(llvm.AtomicRMWBinOpXchg, ptr, val, llvm.AtomicOrderingSequentiallyConsistent, true)
|
||||
if isPointer {
|
||||
oldVal = b.CreateIntToPtr(oldVal, b.i8ptrType, "")
|
||||
}
|
||||
return oldVal, true
|
||||
case "CompareAndSwapInt32", "CompareAndSwapInt64", "CompareAndSwapUint32", "CompareAndSwapUint64", "CompareAndSwapUintptr", "CompareAndSwapPointer":
|
||||
ptr := b.getValue(call.Args[0])
|
||||
old := b.getValue(call.Args[1])
|
||||
newVal := b.getValue(call.Args[2])
|
||||
tuple := b.CreateAtomicCmpXchg(ptr, old, newVal, llvm.AtomicOrderingSequentiallyConsistent, llvm.AtomicOrderingSequentiallyConsistent, true)
|
||||
swapped := b.CreateExtractValue(tuple, 1, "")
|
||||
return swapped, true
|
||||
case "LoadInt32", "LoadInt64", "LoadUint32", "LoadUint64", "LoadUintptr", "LoadPointer":
|
||||
ptr := b.getValue(call.Args[0])
|
||||
val := b.CreateLoad(ptr, "")
|
||||
val.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
|
||||
val.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
|
||||
return val, true
|
||||
case "StoreInt32", "StoreInt64", "StoreUint32", "StoreUint64", "StoreUintptr", "StorePointer":
|
||||
ptr := b.getValue(call.Args[0])
|
||||
val := b.getValue(call.Args[1])
|
||||
store := b.CreateStore(val, ptr)
|
||||
store.SetOrdering(llvm.AtomicOrderingSequentiallyConsistent)
|
||||
store.SetAlignment(b.targetData.PrefTypeAlignment(val.Type())) // required
|
||||
return store, true
|
||||
default:
|
||||
return llvm.Value{}, false
|
||||
}
|
||||
}
|
||||
+4
-6
@@ -34,14 +34,12 @@ const (
|
||||
|
||||
// createCall creates a new call to runtime.<fnName> with the given arguments.
|
||||
func (b *builder) createRuntimeCall(fnName string, args []llvm.Value, name string) llvm.Value {
|
||||
fullName := "runtime." + fnName
|
||||
fn := b.mod.NamedFunction(fullName)
|
||||
if fn.IsNil() {
|
||||
panic("trying to call non-existent function: " + fullName)
|
||||
}
|
||||
llvmFn := b.getFunctionRaw(b.getRuntimeFuncType(fnName), functionInfo{
|
||||
linkName: "runtime." + fnName,
|
||||
})
|
||||
args = append(args, llvm.Undef(b.i8ptrType)) // unused context parameter
|
||||
args = append(args, llvm.ConstPointerNull(b.i8ptrType)) // coroutine handle
|
||||
return b.createCall(fn, args, name)
|
||||
return b.createCall(llvmFn, args, name)
|
||||
}
|
||||
|
||||
// createCall creates a call to the given function with the arguments possibly
|
||||
|
||||
+6
-16
@@ -12,7 +12,7 @@ import (
|
||||
)
|
||||
|
||||
func (b *builder) createMakeChan(expr *ssa.MakeChan) llvm.Value {
|
||||
elementSize := b.targetData.TypeAllocSize(b.getLLVMType(expr.Type().Underlying().(*types.Chan).Elem()))
|
||||
elementSize := b.targetData.TypeAllocSize(b.getLLVMType(expr.Type().(*types.Chan).Elem()))
|
||||
elementSizeValue := llvm.ConstInt(b.uintptrType, elementSize, false)
|
||||
bufSize := b.getValue(expr.Size)
|
||||
b.createChanBoundsCheck(elementSize, bufSize, expr.Size.Type().Underlying().(*types.Basic), expr.Pos())
|
||||
@@ -35,37 +35,27 @@ func (b *builder) createChanSend(instr *ssa.Send) {
|
||||
valueAlloca, valueAllocaCast, valueAllocaSize := b.createTemporaryAlloca(valueType, "chan.value")
|
||||
b.CreateStore(chanValue, valueAlloca)
|
||||
|
||||
// Allocate blockedlist buffer.
|
||||
channelBlockedList := b.mod.GetTypeByName("runtime.channelBlockedList")
|
||||
channelBlockedListAlloca, channelBlockedListAllocaCast, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
|
||||
|
||||
// Do the send.
|
||||
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAllocaCast, channelBlockedListAlloca}, "")
|
||||
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAllocaCast}, "")
|
||||
|
||||
// End the lifetime of the allocas.
|
||||
// End the lifetime of the alloca.
|
||||
// This also works around a bug in CoroSplit, at least in LLVM 8:
|
||||
// https://bugs.llvm.org/show_bug.cgi?id=41742
|
||||
b.emitLifetimeEnd(channelBlockedListAllocaCast, channelBlockedListAllocaSize)
|
||||
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
|
||||
}
|
||||
|
||||
// createChanRecv emits a pseudo chan receive operation. It is lowered to the
|
||||
// actual channel receive operation during goroutine lowering.
|
||||
func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
|
||||
valueType := b.getLLVMType(unop.X.Type().Underlying().(*types.Chan).Elem())
|
||||
valueType := b.getLLVMType(unop.X.Type().(*types.Chan).Elem())
|
||||
ch := b.getValue(unop.X)
|
||||
|
||||
// Allocate memory to receive into.
|
||||
valueAlloca, valueAllocaCast, valueAllocaSize := b.createTemporaryAlloca(valueType, "chan.value")
|
||||
|
||||
// Allocate blockedlist buffer.
|
||||
channelBlockedList := b.mod.GetTypeByName("runtime.channelBlockedList")
|
||||
channelBlockedListAlloca, channelBlockedListAllocaCast, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
|
||||
|
||||
// Do the receive.
|
||||
commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAllocaCast, channelBlockedListAlloca}, "")
|
||||
commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAllocaCast}, "")
|
||||
received := b.CreateLoad(valueAlloca, "chan.received")
|
||||
b.emitLifetimeEnd(channelBlockedListAllocaCast, channelBlockedListAllocaSize)
|
||||
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
|
||||
|
||||
if unop.CommaOk {
|
||||
@@ -127,7 +117,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
|
||||
switch state.Dir {
|
||||
case types.RecvOnly:
|
||||
// Make sure the receive buffer is big enough and has the correct alignment.
|
||||
llvmType := b.getLLVMType(state.Chan.Type().Underlying().(*types.Chan).Elem())
|
||||
llvmType := b.getLLVMType(state.Chan.Type().(*types.Chan).Elem())
|
||||
if size := b.targetData.TypeAllocSize(llvmType); size > recvbufSize {
|
||||
recvbufSize = size
|
||||
}
|
||||
|
||||
+394
-309
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,138 @@
|
||||
package compiler
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"github.com/tinygo-org/tinygo/compiler/ircheck"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"golang.org/x/tools/go/ssa/ssautil"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
var flagUpdate = flag.Bool("update", false, "update all tests")
|
||||
|
||||
func TestCompiler(t *testing.T) {
|
||||
t.Parallel()
|
||||
for _, name := range []string{"basic"} {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
runCompilerTest(t, name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func runCompilerTest(t *testing.T, name string) {
|
||||
// Read the AST in memory.
|
||||
path := filepath.Join("testdata", name+".go")
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, path, nil, parser.ParseComments)
|
||||
if err != nil {
|
||||
t.Fatal("could not parse Go source file:", err)
|
||||
}
|
||||
files := []*ast.File{f}
|
||||
|
||||
// Create Go SSA from the AST.
|
||||
var typecheckErrors []error
|
||||
var typecheckErrorsLock sync.Mutex
|
||||
typesConfig := types.Config{
|
||||
Error: func(err error) {
|
||||
typecheckErrorsLock.Lock()
|
||||
defer typecheckErrorsLock.Unlock()
|
||||
typecheckErrors = append(typecheckErrors, err)
|
||||
},
|
||||
Importer: simpleImporter{},
|
||||
Sizes: types.SizesFor("gccgo", "arm"),
|
||||
}
|
||||
pkg, _, err := ssautil.BuildPackage(&typesConfig, fset, types.NewPackage("main", ""), files, ssa.SanityCheckFunctions|ssa.BareInits|ssa.GlobalDebug)
|
||||
for _, err := range typecheckErrors {
|
||||
t.Error(err)
|
||||
}
|
||||
if err != nil && len(typecheckErrors) == 0 {
|
||||
// Only report errors when no type errors are found (an
|
||||
// unexpected condition).
|
||||
t.Error(err)
|
||||
}
|
||||
if t.Failed() {
|
||||
return
|
||||
}
|
||||
|
||||
// Configure the compiler.
|
||||
config := compileopts.Config{
|
||||
Options: &compileopts.Options{},
|
||||
Target: &compileopts.TargetSpec{
|
||||
Triple: "armv7m-none-eabi",
|
||||
BuildTags: []string{"cortexm", "baremetal", "linux", "arm"},
|
||||
Scheduler: "tasks",
|
||||
},
|
||||
}
|
||||
machine, err := NewTargetMachine(&config)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
c := newCompilerContext("main", machine, &config)
|
||||
c.runtimePkg = types.NewPackage("runtime", "runtime")
|
||||
c.taskPkg = types.NewPackage("internal/task", "task")
|
||||
irbuilder := c.ctx.NewBuilder()
|
||||
defer irbuilder.Dispose()
|
||||
|
||||
// Create LLVM IR from the Go SSA.
|
||||
c.createPackage(pkg, irbuilder)
|
||||
|
||||
// Check the IR with the LLVM verifier.
|
||||
if err := llvm.VerifyModule(c.mod, llvm.PrintMessageAction); err != nil {
|
||||
t.Error("verification error after IR construction")
|
||||
}
|
||||
|
||||
// Check the IR with our own verifier (which checks for different things).
|
||||
errs := ircheck.Module(c.mod)
|
||||
for _, err := range errs {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// Check whether the IR matches the expected IR.
|
||||
ir := c.mod.String()
|
||||
ir = ir[strings.Index(ir, "\ntarget datalayout = ")+1:]
|
||||
outfile := filepath.Join("testdata", name+".ll")
|
||||
if *flagUpdate {
|
||||
err := ioutil.WriteFile(outfile, []byte(ir), 0666)
|
||||
if err != nil {
|
||||
t.Error("could not read output file:", err)
|
||||
}
|
||||
} else {
|
||||
ir2, err := ioutil.ReadFile(outfile)
|
||||
if err != nil {
|
||||
t.Fatal("could not read input file:", err)
|
||||
}
|
||||
ir2 = bytes.Replace(ir2, []byte("\r\n"), []byte("\n"), -1)
|
||||
if ir != string(ir2) {
|
||||
t.Error("output did not match")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// simpleImporter implements the types.Importer interface, but only allows
|
||||
// importing the unsafe package.
|
||||
type simpleImporter struct {
|
||||
}
|
||||
|
||||
// Import implements the Importer interface. For testing usage only: it only
|
||||
// supports importing the unsafe package.
|
||||
func (i simpleImporter) Import(path string) (*types.Package, error) {
|
||||
switch path {
|
||||
case "unsafe":
|
||||
return types.Unsafe, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("importer not implemented for package %s", path)
|
||||
}
|
||||
}
|
||||
+30
-127
@@ -15,8 +15,6 @@ package compiler
|
||||
|
||||
import (
|
||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||
"github.com/tinygo-org/tinygo/ir"
|
||||
"go/types"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
@@ -26,11 +24,9 @@ import (
|
||||
// calls.
|
||||
func (b *builder) deferInitFunc() {
|
||||
// Some setup.
|
||||
b.deferFuncs = make(map[*ir.Function]int)
|
||||
b.deferFuncs = make(map[*ssa.Function]int)
|
||||
b.deferInvokeFuncs = make(map[string]int)
|
||||
b.deferClosureFuncs = make(map[*ir.Function]int)
|
||||
b.deferExprFuncs = make(map[ssa.Value]int)
|
||||
b.deferBuiltinFuncs = make(map[ssa.Value]deferBuiltin)
|
||||
b.deferClosureFuncs = make(map[*ssa.Function]int)
|
||||
|
||||
// Create defer list pointer.
|
||||
deferType := llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)
|
||||
@@ -107,13 +103,12 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
|
||||
} else if callee, ok := instr.Call.Value.(*ssa.Function); ok {
|
||||
// Regular function call.
|
||||
fn := b.ir.GetFunction(callee)
|
||||
|
||||
if _, ok := b.deferFuncs[fn]; !ok {
|
||||
b.deferFuncs[fn] = len(b.allDeferFuncs)
|
||||
b.allDeferFuncs = append(b.allDeferFuncs, fn)
|
||||
if _, ok := b.deferFuncs[callee]; !ok {
|
||||
b.deferFuncs[callee] = len(b.allDeferFuncs)
|
||||
b.allDeferFuncs = append(b.allDeferFuncs, callee)
|
||||
}
|
||||
callback := llvm.ConstInt(b.uintptrType, uint64(b.deferFuncs[fn]), false)
|
||||
callback := llvm.ConstInt(b.uintptrType, uint64(b.deferFuncs[callee]), false)
|
||||
|
||||
// Collect all values to be put in the struct (starting with
|
||||
// runtime._defer fields).
|
||||
@@ -135,7 +130,7 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
context := b.CreateExtractValue(closure, 0, "")
|
||||
|
||||
// Get the callback number.
|
||||
fn := b.ir.GetFunction(makeClosure.Fn.(*ssa.Function))
|
||||
fn := makeClosure.Fn.(*ssa.Function)
|
||||
if _, ok := b.deferClosureFuncs[fn]; !ok {
|
||||
b.deferClosureFuncs[fn] = len(b.allDeferFuncs)
|
||||
b.allDeferFuncs = append(b.allDeferFuncs, makeClosure)
|
||||
@@ -154,54 +149,9 @@ func (b *builder) createDefer(instr *ssa.Defer) {
|
||||
values = append(values, context)
|
||||
valueTypes = append(valueTypes, context.Type())
|
||||
|
||||
} else if builtin, ok := instr.Call.Value.(*ssa.Builtin); ok {
|
||||
var funcName string
|
||||
switch builtin.Name() {
|
||||
case "close":
|
||||
funcName = "chanClose"
|
||||
default:
|
||||
b.addError(instr.Pos(), "todo: Implement defer for "+builtin.Name())
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := b.deferBuiltinFuncs[instr.Call.Value]; !ok {
|
||||
b.deferBuiltinFuncs[instr.Call.Value] = deferBuiltin{
|
||||
funcName,
|
||||
len(b.allDeferFuncs),
|
||||
}
|
||||
b.allDeferFuncs = append(b.allDeferFuncs, instr.Call.Value)
|
||||
}
|
||||
callback := llvm.ConstInt(b.uintptrType, uint64(b.deferBuiltinFuncs[instr.Call.Value].callback), false)
|
||||
|
||||
// Collect all values to be put in the struct (starting with
|
||||
// runtime._defer fields).
|
||||
values = []llvm.Value{callback, next}
|
||||
for _, param := range instr.Call.Args {
|
||||
llvmParam := b.getValue(param)
|
||||
values = append(values, llvmParam)
|
||||
valueTypes = append(valueTypes, llvmParam.Type())
|
||||
}
|
||||
|
||||
} else {
|
||||
funcValue := b.getValue(instr.Call.Value)
|
||||
|
||||
if _, ok := b.deferExprFuncs[instr.Call.Value]; !ok {
|
||||
b.deferExprFuncs[instr.Call.Value] = len(b.allDeferFuncs)
|
||||
b.allDeferFuncs = append(b.allDeferFuncs, &instr.Call)
|
||||
}
|
||||
|
||||
callback := llvm.ConstInt(b.uintptrType, uint64(b.deferExprFuncs[instr.Call.Value]), false)
|
||||
|
||||
// Collect all values to be put in the struct (starting with
|
||||
// runtime._defer fields, followed by all parameters including the
|
||||
// context pointer).
|
||||
values = []llvm.Value{callback, next, funcValue}
|
||||
valueTypes = append(valueTypes, funcValue.Type())
|
||||
for _, param := range instr.Call.Args {
|
||||
llvmParam := b.getValue(param)
|
||||
values = append(values, llvmParam)
|
||||
valueTypes = append(valueTypes, llvmParam.Type())
|
||||
}
|
||||
b.addError(instr.Pos(), "todo: defer on uncommon function call type")
|
||||
return
|
||||
}
|
||||
|
||||
// Make a struct out of the collected values to put in the defer frame.
|
||||
@@ -251,10 +201,10 @@ func (b *builder) createRunDefers() {
|
||||
// }
|
||||
|
||||
// Create loop.
|
||||
loophead := b.ctx.AddBasicBlock(b.fn.LLVMFn, "rundefers.loophead")
|
||||
loop := b.ctx.AddBasicBlock(b.fn.LLVMFn, "rundefers.loop")
|
||||
unreachable := b.ctx.AddBasicBlock(b.fn.LLVMFn, "rundefers.default")
|
||||
end := b.ctx.AddBasicBlock(b.fn.LLVMFn, "rundefers.end")
|
||||
loophead := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.loophead")
|
||||
loop := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.loop")
|
||||
unreachable := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.default")
|
||||
end := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.end")
|
||||
b.CreateBr(loophead)
|
||||
|
||||
// Create loop head:
|
||||
@@ -286,28 +236,21 @@ func (b *builder) createRunDefers() {
|
||||
// Create switch case, for example:
|
||||
// case 0:
|
||||
// // run first deferred call
|
||||
block := b.ctx.AddBasicBlock(b.fn.LLVMFn, "rundefers.callback")
|
||||
block := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.callback")
|
||||
sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), block)
|
||||
b.SetInsertPointAtEnd(block)
|
||||
switch callback := callback.(type) {
|
||||
case *ssa.CallCommon:
|
||||
// Call on an value or interface value.
|
||||
|
||||
// Get the real defer struct type and cast to it.
|
||||
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
|
||||
|
||||
// Call on an interface value.
|
||||
if !callback.IsInvoke() {
|
||||
//Expect funcValue to be passed through the defer frame.
|
||||
valueTypes = append(valueTypes, b.getFuncType(callback.Signature()))
|
||||
} else {
|
||||
//Expect typecode
|
||||
valueTypes = append(valueTypes, b.uintptrType, b.i8ptrType)
|
||||
panic("expected an invoke call, not a direct call")
|
||||
}
|
||||
|
||||
// Get the real defer struct type and cast to it.
|
||||
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0), b.uintptrType, b.i8ptrType}
|
||||
for _, arg := range callback.Args {
|
||||
valueTypes = append(valueTypes, b.getLLVMType(arg.Type()))
|
||||
}
|
||||
|
||||
deferFrameType := b.ctx.StructType(valueTypes, false)
|
||||
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||
|
||||
@@ -320,37 +263,21 @@ func (b *builder) createRunDefers() {
|
||||
forwardParams = append(forwardParams, forwardParam)
|
||||
}
|
||||
|
||||
var fnPtr llvm.Value
|
||||
// Isolate the typecode.
|
||||
typecode, forwardParams := forwardParams[0], forwardParams[1:]
|
||||
|
||||
if !callback.IsInvoke() {
|
||||
// Isolate the func value.
|
||||
funcValue := forwardParams[0]
|
||||
forwardParams = forwardParams[1:]
|
||||
|
||||
//Get function pointer and context
|
||||
fp, context := b.decodeFuncValue(funcValue, callback.Signature())
|
||||
fnPtr = fp
|
||||
|
||||
//Pass context
|
||||
forwardParams = append(forwardParams, context)
|
||||
} else {
|
||||
// Isolate the typecode.
|
||||
typecode := forwardParams[0]
|
||||
forwardParams = forwardParams[1:]
|
||||
fnPtr = b.getInvokePtr(callback, typecode)
|
||||
|
||||
// Add the context parameter. An interface call cannot also be a
|
||||
// closure but we have to supply the parameter anyway for platforms
|
||||
// with a strict calling convention.
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||
}
|
||||
// Add the context parameter. An interface call cannot also be a
|
||||
// closure but we have to supply the parameter anyway for platforms
|
||||
// with a strict calling convention.
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||
|
||||
// Parent coroutine handle.
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||
|
||||
fnPtr := b.getInvokePtr(callback, typecode)
|
||||
b.createCall(fnPtr, forwardParams, "")
|
||||
|
||||
case *ir.Function:
|
||||
case *ssa.Function:
|
||||
// Direct call.
|
||||
|
||||
// Get the real defer struct type and cast to it.
|
||||
@@ -372,7 +299,7 @@ func (b *builder) createRunDefers() {
|
||||
|
||||
// Plain TinyGo functions add some extra parameters to implement async functionality and function recievers.
|
||||
// These parameters should not be supplied when calling into an external C/ASM function.
|
||||
if !callback.IsExported() {
|
||||
if !b.getFunctionInfo(callback).exported {
|
||||
// Add the context parameter. We know it is ignored by the receiving
|
||||
// function, but we have to pass one anyway.
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||
@@ -382,11 +309,11 @@ func (b *builder) createRunDefers() {
|
||||
}
|
||||
|
||||
// Call real function.
|
||||
b.createCall(callback.LLVMFn, forwardParams, "")
|
||||
b.createCall(b.getFunction(callback), forwardParams, "")
|
||||
|
||||
case *ssa.MakeClosure:
|
||||
// Get the real defer struct type and cast to it.
|
||||
fn := b.ir.GetFunction(callback.Fn.(*ssa.Function))
|
||||
fn := callback.Fn.(*ssa.Function)
|
||||
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
|
||||
params := fn.Signature.Params()
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
@@ -409,32 +336,8 @@ func (b *builder) createRunDefers() {
|
||||
forwardParams = append(forwardParams, llvm.Undef(b.i8ptrType))
|
||||
|
||||
// Call deferred function.
|
||||
b.createCall(fn.LLVMFn, forwardParams, "")
|
||||
case *ssa.Builtin:
|
||||
db := b.deferBuiltinFuncs[callback]
|
||||
b.createCall(b.getFunction(fn), forwardParams, "")
|
||||
|
||||
//Get parameter types
|
||||
valueTypes := []llvm.Type{b.uintptrType, llvm.PointerType(b.getLLVMRuntimeType("_defer"), 0)}
|
||||
|
||||
//Get signature from call results
|
||||
params := callback.Type().Underlying().(*types.Signature).Params()
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
valueTypes = append(valueTypes, b.getLLVMType(params.At(i).Type()))
|
||||
}
|
||||
|
||||
deferFrameType := b.ctx.StructType(valueTypes, false)
|
||||
deferFramePtr := b.CreateBitCast(deferData, llvm.PointerType(deferFrameType, 0), "deferFrame")
|
||||
|
||||
// Extract the params from the struct.
|
||||
var forwardParams []llvm.Value
|
||||
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
|
||||
for i := 0; i < params.Len(); i++ {
|
||||
gep := b.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(b.ctx.Int32Type(), uint64(i+2), false)}, "gep")
|
||||
forwardParam := b.CreateLoad(gep, "param")
|
||||
forwardParams = append(forwardParams, forwardParam)
|
||||
}
|
||||
|
||||
b.createRuntimeCall(db.funcName, forwardParams, "")
|
||||
default:
|
||||
panic("unknown deferred function type")
|
||||
}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import (
|
||||
// makeError makes it easy to create an error from a token.Pos with a message.
|
||||
func (c *compilerContext) makeError(pos token.Pos, msg string) types.Error {
|
||||
return types.Error{
|
||||
Fset: c.ir.Program.Fset,
|
||||
Fset: c.program.Fset,
|
||||
Pos: pos,
|
||||
Msg: msg,
|
||||
}
|
||||
|
||||
+12
-2
@@ -5,6 +5,7 @@ package compiler
|
||||
|
||||
import (
|
||||
"go/types"
|
||||
"strings"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
@@ -149,7 +150,16 @@ func (b *builder) parseMakeClosure(expr *ssa.MakeClosure) (llvm.Value, error) {
|
||||
if len(expr.Bindings) == 0 {
|
||||
panic("unexpected: MakeClosure without bound variables")
|
||||
}
|
||||
f := b.ir.GetFunction(expr.Fn.(*ssa.Function))
|
||||
f := expr.Fn.(*ssa.Function)
|
||||
llvmFn := b.getFunction(f)
|
||||
|
||||
if strings.HasSuffix(f.Name(), "$bound") && llvmFn.IsDeclaration() {
|
||||
// Hack: the ssa package does not expose bound methods so make sure
|
||||
// they're built here when necessary.
|
||||
irbuilder := b.ctx.NewBuilder()
|
||||
defer irbuilder.Dispose()
|
||||
b.createFunction(irbuilder, f, llvmFn)
|
||||
}
|
||||
|
||||
// Collect all bound variables.
|
||||
boundVars := make([]llvm.Value, len(expr.Bindings))
|
||||
@@ -164,5 +174,5 @@ func (b *builder) parseMakeClosure(expr *ssa.MakeClosure) (llvm.Value, error) {
|
||||
context := b.emitPointerPack(boundVars)
|
||||
|
||||
// Create the closure.
|
||||
return b.createFuncValue(f.LLVMFn, context, f.Signature), nil
|
||||
return b.createFuncValue(llvmFn, context, f.Signature), nil
|
||||
}
|
||||
|
||||
+7
-21
@@ -7,6 +7,7 @@ import (
|
||||
"go/token"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
@@ -19,30 +20,17 @@ import (
|
||||
// Because a go statement doesn't return anything, return undef.
|
||||
func (b *builder) createGoInstruction(funcPtr llvm.Value, params []llvm.Value, prefix string, pos token.Pos) llvm.Value {
|
||||
paramBundle := b.emitPointerPack(params)
|
||||
var callee, stackSize llvm.Value
|
||||
var callee llvm.Value
|
||||
switch b.Scheduler() {
|
||||
case "none", "tasks":
|
||||
callee = b.createGoroutineStartWrapper(funcPtr, prefix, pos)
|
||||
if b.AutomaticStackSize() {
|
||||
// The stack size is not known until after linking. Call a dummy
|
||||
// function that will be replaced with a load from a special ELF
|
||||
// section that contains the stack size (and is modified after
|
||||
// linking).
|
||||
stackSize = b.createCall(b.mod.NamedFunction("internal/task.getGoroutineStackSize"), []llvm.Value{callee, llvm.Undef(b.i8ptrType), llvm.Undef(b.i8ptrType)}, "stacksize")
|
||||
} else {
|
||||
// The stack size is fixed at compile time. By emitting it here as a
|
||||
// constant, it can be optimized.
|
||||
stackSize = llvm.ConstInt(b.uintptrType, b.Target.DefaultStackSize, false)
|
||||
}
|
||||
case "coroutines":
|
||||
callee = b.CreatePtrToInt(funcPtr, b.uintptrType, "")
|
||||
// There is no goroutine stack size: coroutines are used instead of
|
||||
// stacks.
|
||||
stackSize = llvm.Undef(b.uintptrType)
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
b.createCall(b.mod.NamedFunction("internal/task.start"), []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType), llvm.ConstPointerNull(b.i8ptrType)}, "")
|
||||
start := b.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
|
||||
b.createCall(start, []llvm.Value{callee, paramBundle, llvm.Undef(b.i8ptrType), llvm.ConstPointerNull(b.i8ptrType)}, "")
|
||||
return llvm.Undef(funcPtr.Type().ElementType().ReturnType())
|
||||
}
|
||||
|
||||
@@ -81,14 +69,13 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
|
||||
// Create the wrapper.
|
||||
wrapperType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType}, false)
|
||||
wrapper = llvm.AddFunction(c.mod, name+"$gowrapper", wrapperType)
|
||||
wrapper.SetLinkage(llvm.InternalLinkage)
|
||||
wrapper.SetLinkage(llvm.PrivateLinkage)
|
||||
wrapper.SetUnnamedAddr(true)
|
||||
wrapper.AddAttributeAtIndex(-1, c.ctx.CreateStringAttribute("tinygo-gowrapper", name))
|
||||
entry := c.ctx.AddBasicBlock(wrapper, "entry")
|
||||
builder.SetInsertPointAtEnd(entry)
|
||||
|
||||
if c.Debug() {
|
||||
pos := c.ir.Program.Fset.Position(pos)
|
||||
pos := c.program.Fset.Position(pos)
|
||||
diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
|
||||
File: c.getDIFile(pos.Filename),
|
||||
Parameters: nil, // do not show parameters in debugger
|
||||
@@ -140,12 +127,11 @@ func (c *compilerContext) createGoroutineStartWrapper(fn llvm.Value, prefix stri
|
||||
wrapper = llvm.AddFunction(c.mod, prefix+".gowrapper", wrapperType)
|
||||
wrapper.SetLinkage(llvm.InternalLinkage)
|
||||
wrapper.SetUnnamedAddr(true)
|
||||
wrapper.AddAttributeAtIndex(-1, c.ctx.CreateStringAttribute("tinygo-gowrapper", ""))
|
||||
entry := c.ctx.AddBasicBlock(wrapper, "entry")
|
||||
builder.SetInsertPointAtEnd(entry)
|
||||
|
||||
if c.Debug() {
|
||||
pos := c.ir.Program.Fset.Position(pos)
|
||||
pos := c.program.Fset.Position(pos)
|
||||
diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{
|
||||
File: c.getDIFile(pos.Filename),
|
||||
Parameters: nil, // do not show parameters in debugger
|
||||
|
||||
@@ -163,44 +163,6 @@ func (b *builder) emitSVCall(args []ssa.Value) (llvm.Value, error) {
|
||||
return b.CreateCall(target, llvmArgs, ""), nil
|
||||
}
|
||||
|
||||
// This is a compiler builtin which emits an inline SVCall instruction. It can
|
||||
// be one of:
|
||||
//
|
||||
// func SVCall0(num uintptr) uintptr
|
||||
// func SVCall1(num uintptr, a1 interface{}) uintptr
|
||||
// func SVCall2(num uintptr, a1, a2 interface{}) uintptr
|
||||
// func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
|
||||
// func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
|
||||
//
|
||||
// The num parameter must be a constant. All other parameters may be any scalar
|
||||
// value supported by LLVM inline assembly.
|
||||
// Same as emitSVCall but for AArch64
|
||||
func (b *builder) emitSV64Call(args []ssa.Value) (llvm.Value, error) {
|
||||
num, _ := constant.Uint64Val(args[0].(*ssa.Const).Value)
|
||||
llvmArgs := []llvm.Value{}
|
||||
argTypes := []llvm.Type{}
|
||||
asm := "svc #" + strconv.FormatUint(num, 10)
|
||||
constraints := "={x0}"
|
||||
for i, arg := range args[1:] {
|
||||
arg = arg.(*ssa.MakeInterface).X
|
||||
if i == 0 {
|
||||
constraints += ",0"
|
||||
} else {
|
||||
constraints += ",{x" + strconv.Itoa(i) + "}"
|
||||
}
|
||||
llvmValue := b.getValue(arg)
|
||||
llvmArgs = append(llvmArgs, llvmValue)
|
||||
argTypes = append(argTypes, llvmValue.Type())
|
||||
}
|
||||
// Implement the ARM64 calling convention by marking x1-x7 as
|
||||
// clobbered. x0 is used as an output register so doesn't have to be
|
||||
// marked as clobbered.
|
||||
constraints += ",~{x1},~{x2},~{x3},~{x4},~{x5},~{x6},~{x7}"
|
||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||
target := llvm.InlineAsm(fnType, asm, constraints, true, false, 0)
|
||||
return b.CreateCall(target, llvmArgs, ""), nil
|
||||
}
|
||||
|
||||
// This is a compiler builtin which emits CSR instructions. It can be one of:
|
||||
//
|
||||
// func (csr CSR) Get() uintptr
|
||||
|
||||
+87
-21
@@ -11,7 +11,6 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/tinygo-org/tinygo/ir"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
@@ -236,7 +235,7 @@ func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value {
|
||||
return llvm.ConstGEP(global, []llvm.Value{zero, zero})
|
||||
}
|
||||
|
||||
ms := c.ir.Program.MethodSets.MethodSet(typ)
|
||||
ms := c.program.MethodSets.MethodSet(typ)
|
||||
if ms.Len() == 0 {
|
||||
// no methods, so can leave that one out
|
||||
return llvm.ConstPointerNull(llvm.PointerType(c.getLLVMRuntimeType("interfaceMethodInfo"), 0))
|
||||
@@ -247,15 +246,23 @@ func (c *compilerContext) getTypeMethodSet(typ types.Type) llvm.Value {
|
||||
for i := 0; i < ms.Len(); i++ {
|
||||
method := ms.At(i)
|
||||
signatureGlobal := c.getMethodSignature(method.Obj().(*types.Func))
|
||||
f := c.ir.GetFunction(c.ir.Program.MethodValue(method))
|
||||
if f.LLVMFn.IsNil() {
|
||||
fn := c.program.MethodValue(method)
|
||||
llvmFn := c.getFunction(fn)
|
||||
if llvmFn.IsNil() {
|
||||
// compiler error, so panic
|
||||
panic("cannot find function: " + f.LinkName())
|
||||
panic("cannot find function: " + c.getFunctionInfo(fn).linkName)
|
||||
}
|
||||
fn := c.getInterfaceInvokeWrapper(f)
|
||||
if isAnonymous(typ) && llvmFn.IsDeclaration() {
|
||||
// Inline types may also have methods when they embed interface
|
||||
// types with methods. Example: struct{ error }
|
||||
irbuilder := c.ctx.NewBuilder()
|
||||
defer irbuilder.Dispose()
|
||||
c.createFunction(irbuilder, fn, llvmFn)
|
||||
}
|
||||
wrapper := c.getInterfaceInvokeWrapper(fn, llvmFn)
|
||||
methodInfo := llvm.ConstNamedStruct(interfaceMethodInfoType, []llvm.Value{
|
||||
signatureGlobal,
|
||||
llvm.ConstPtrToInt(fn, c.uintptrType),
|
||||
llvm.ConstPtrToInt(wrapper, c.uintptrType),
|
||||
})
|
||||
methods[i] = methodInfo
|
||||
}
|
||||
@@ -303,7 +310,7 @@ func (c *compilerContext) getInterfaceMethodSet(typ types.Type) llvm.Value {
|
||||
// external *i8 indicating the indicating the signature of this method. It is
|
||||
// used during the interface lowering pass.
|
||||
func (c *compilerContext) getMethodSignature(method *types.Func) llvm.Value {
|
||||
signature := ir.MethodSignature(method)
|
||||
signature := methodSignature(method)
|
||||
signatureGlobal := c.mod.NamedGlobal("func " + signature)
|
||||
if signatureGlobal.IsNil() {
|
||||
signatureGlobal = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), "func "+signature)
|
||||
@@ -357,8 +364,8 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
|
||||
// value.
|
||||
|
||||
prevBlock := b.GetInsertBlock()
|
||||
okBlock := b.ctx.AddBasicBlock(b.fn.LLVMFn, "typeassert.ok")
|
||||
nextBlock := b.ctx.AddBasicBlock(b.fn.LLVMFn, "typeassert.next")
|
||||
okBlock := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.ok")
|
||||
nextBlock := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.next")
|
||||
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
|
||||
b.CreateCondBr(commaOk, okBlock, nextBlock)
|
||||
|
||||
@@ -436,8 +443,8 @@ func (b *builder) getInvokeCall(instr *ssa.CallCommon) (llvm.Value, []llvm.Value
|
||||
// value, dereferences or unpacks it if necessary, and calls the real method.
|
||||
// If the method to wrap has a pointer receiver, no wrapping is necessary and
|
||||
// the function is returned directly.
|
||||
func (c *compilerContext) getInterfaceInvokeWrapper(f *ir.Function) llvm.Value {
|
||||
wrapperName := f.LinkName() + "$invoke"
|
||||
func (c *compilerContext) getInterfaceInvokeWrapper(fn *ssa.Function, llvmFn llvm.Value) llvm.Value {
|
||||
wrapperName := llvmFn.Name() + "$invoke"
|
||||
wrapper := c.mod.NamedFunction(wrapperName)
|
||||
if !wrapper.IsNil() {
|
||||
// Wrapper already created. Return it directly.
|
||||
@@ -445,7 +452,7 @@ func (c *compilerContext) getInterfaceInvokeWrapper(f *ir.Function) llvm.Value {
|
||||
}
|
||||
|
||||
// Get the expanded receiver type.
|
||||
receiverType := c.getLLVMType(f.Params[0].Type())
|
||||
receiverType := c.getLLVMType(fn.Params[0].Type())
|
||||
var expandedReceiverType []llvm.Type
|
||||
for _, info := range expandFormalParamType(receiverType, "", nil) {
|
||||
expandedReceiverType = append(expandedReceiverType, info.llvmType)
|
||||
@@ -457,15 +464,15 @@ func (c *compilerContext) getInterfaceInvokeWrapper(f *ir.Function) llvm.Value {
|
||||
// Casting a function signature to a different signature and calling it
|
||||
// with a receiver pointer bitcasted to *i8 (as done in calls on an
|
||||
// interface) is hopefully a safe (defined) operation.
|
||||
return f.LLVMFn
|
||||
return llvmFn
|
||||
}
|
||||
|
||||
// create wrapper function
|
||||
fnType := f.LLVMFn.Type().ElementType()
|
||||
fnType := llvmFn.Type().ElementType()
|
||||
paramTypes := append([]llvm.Type{c.i8ptrType}, fnType.ParamTypes()[len(expandedReceiverType):]...)
|
||||
wrapFnType := llvm.FunctionType(fnType.ReturnType(), paramTypes, false)
|
||||
wrapper = llvm.AddFunction(c.mod, wrapperName, wrapFnType)
|
||||
if f.LLVMFn.LastParam().Name() == "parentHandle" {
|
||||
if llvmFn.LastParam().Name() == "parentHandle" {
|
||||
wrapper.LastParam().SetName("parentHandle")
|
||||
}
|
||||
|
||||
@@ -481,8 +488,8 @@ func (c *compilerContext) getInterfaceInvokeWrapper(f *ir.Function) llvm.Value {
|
||||
|
||||
// add debug info if needed
|
||||
if c.Debug() {
|
||||
pos := c.ir.Program.Fset.Position(f.Pos())
|
||||
difunc := c.attachDebugInfoRaw(f, wrapper, "$invoke", pos.Filename, pos.Line)
|
||||
pos := c.program.Fset.Position(fn.Pos())
|
||||
difunc := c.attachDebugInfoRaw(fn, wrapper, "$invoke", pos.Filename, pos.Line)
|
||||
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), difunc, llvm.Metadata{})
|
||||
}
|
||||
|
||||
@@ -492,13 +499,72 @@ func (c *compilerContext) getInterfaceInvokeWrapper(f *ir.Function) llvm.Value {
|
||||
|
||||
receiverValue := b.emitPointerUnpack(wrapper.Param(0), []llvm.Type{receiverType})[0]
|
||||
params := append(b.expandFormalParam(receiverValue), wrapper.Params()[1:]...)
|
||||
if f.LLVMFn.Type().ElementType().ReturnType().TypeKind() == llvm.VoidTypeKind {
|
||||
b.CreateCall(f.LLVMFn, params, "")
|
||||
if llvmFn.Type().ElementType().ReturnType().TypeKind() == llvm.VoidTypeKind {
|
||||
b.CreateCall(llvmFn, params, "")
|
||||
b.CreateRetVoid()
|
||||
} else {
|
||||
ret := b.CreateCall(f.LLVMFn, params, "ret")
|
||||
ret := b.CreateCall(llvmFn, params, "ret")
|
||||
b.CreateRet(ret)
|
||||
}
|
||||
|
||||
return wrapper
|
||||
}
|
||||
|
||||
// isAnonymous returns true if (and only if) this is an anonymous type: one that
|
||||
// is created inline. It can have methods if it embeds a type with methods.
|
||||
func isAnonymous(typ types.Type) bool {
|
||||
if t, ok := typ.(*types.Pointer); ok {
|
||||
typ = t.Elem()
|
||||
}
|
||||
if _, ok := typ.(*types.Named); !ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// methodSignature creates a readable version of a method signature (including
|
||||
// the function name, excluding the receiver name). This string is used
|
||||
// internally to match interfaces and to call the correct method on an
|
||||
// interface. Examples:
|
||||
//
|
||||
// String() string
|
||||
// Read([]byte) (int, error)
|
||||
func methodSignature(method *types.Func) string {
|
||||
return method.Name() + signature(method.Type().(*types.Signature))
|
||||
}
|
||||
|
||||
// Make a readable version of a function (pointer) signature.
|
||||
// Examples:
|
||||
//
|
||||
// () string
|
||||
// (string, int) (int, error)
|
||||
func signature(sig *types.Signature) string {
|
||||
s := ""
|
||||
if sig.Params().Len() == 0 {
|
||||
s += "()"
|
||||
} else {
|
||||
s += "("
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
if i > 0 {
|
||||
s += ", "
|
||||
}
|
||||
s += sig.Params().At(i).Type().String()
|
||||
}
|
||||
s += ")"
|
||||
}
|
||||
if sig.Results().Len() == 0 {
|
||||
// keep as-is
|
||||
} else if sig.Results().Len() == 1 {
|
||||
s += " " + sig.Results().At(0).Type().String()
|
||||
} else {
|
||||
s += " ("
|
||||
for i := 0; i < sig.Results().Len(); i++ {
|
||||
if i > 0 {
|
||||
s += ", "
|
||||
}
|
||||
s += sig.Results().At(i).Type().String()
|
||||
}
|
||||
s += ")"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
|
||||
|
||||
// Create a new global of type runtime/interrupt.handle. Globals of this
|
||||
// type are lowered in the interrupt lowering pass.
|
||||
globalType := b.ir.Program.ImportedPackage("runtime/interrupt").Type("handle").Type()
|
||||
globalType := b.program.ImportedPackage("runtime/interrupt").Type("handle").Type()
|
||||
globalLLVMType := b.getLLVMType(globalType)
|
||||
globalName := "runtime/interrupt.$interrupt" + strconv.FormatInt(id.Int64(), 10)
|
||||
if global := b.mod.NamedGlobal(globalName); !global.IsNil() {
|
||||
@@ -56,7 +56,7 @@ func (b *builder) createInterruptGlobal(instr *ssa.CallCommon) (llvm.Value, erro
|
||||
|
||||
// Add debug info to the interrupt global.
|
||||
if b.Debug() {
|
||||
pos := b.ir.Program.Fset.Position(instr.Pos())
|
||||
pos := b.program.Fset.Position(instr.Pos())
|
||||
diglobal := b.dibuilder.CreateGlobalVariableExpression(b.getDIFile(pos.Filename), llvm.DIGlobalVariableExpression{
|
||||
Name: "interrupt" + strconv.FormatInt(id.Int64(), 10),
|
||||
LinkageName: globalName,
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
// +build none
|
||||
|
||||
// This file generates runtimetypes.go from the AST of the TinyGo runtime
|
||||
// package. This type information is necessary to avoid having to compile the
|
||||
// runtime to compile any package.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/token"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/tools/go/packages"
|
||||
)
|
||||
|
||||
// The list of runtime types known by the compiler.
|
||||
var runtimeTypes = []string{
|
||||
// panic, recover
|
||||
"_defer",
|
||||
// strings
|
||||
"_string", "stringIterator",
|
||||
// map
|
||||
"hashmap", "hashmapBucket", "hashmapIterator",
|
||||
// channel
|
||||
"channel", "channelBlockedList", "chanSelectState",
|
||||
// interface
|
||||
"_interface", "interfaceMethodInfo", "typecodeID", "structField", "typeInInterface",
|
||||
// func
|
||||
"funcValue", "funcValueWithSignature",
|
||||
}
|
||||
|
||||
// The list of runtime calls known to the compiler.
|
||||
var runtimeCalls = []string{
|
||||
// panic, recover
|
||||
"_panic", "_recover",
|
||||
"nilPanic", "lookupPanic", "slicePanic", "chanMakePanic", "negativeShiftPanic",
|
||||
// string
|
||||
"stringEqual", "stringLess",
|
||||
"stringConcat",
|
||||
"stringFromBytes", "stringToBytes",
|
||||
"stringFromRunes", "stringToRunes",
|
||||
"stringFromUnicode",
|
||||
"stringNext",
|
||||
// complex
|
||||
"complex64div", "complex128div",
|
||||
// slice
|
||||
"sliceAppend", "sliceCopy",
|
||||
// memory
|
||||
"alloc", "trackPointer",
|
||||
// print builtin
|
||||
"printbool",
|
||||
"printint8", "printuint8",
|
||||
"printint16", "printuint16",
|
||||
"printint32", "printuint32",
|
||||
"printint64", "printuint64",
|
||||
"printfloat32", "printfloat64",
|
||||
"printcomplex64", "printcomplex128",
|
||||
"printstring", "printspace", "printnl",
|
||||
"printptr", "printmap", "printitf",
|
||||
// hashmap
|
||||
"hashmapMake", "hashmapLen", "hashmapNext",
|
||||
"hashmapStringGet", "hashmapStringSet", "hashmapStringDelete",
|
||||
"hashmapInterfaceGet", "hashmapInterfaceSet", "hashmapInterfaceDelete",
|
||||
"hashmapBinaryGet", "hashmapBinarySet", "hashmapBinaryDelete",
|
||||
// channel, concurrency
|
||||
"tryChanSelect", "chanMake", "chanSend", "chanRecv", "chanClose", "chanSelect",
|
||||
"deadlock",
|
||||
// interface, reflect
|
||||
"interfaceEqual", "interfaceImplements", "interfaceMethod",
|
||||
"typeAssert", "interfaceTypeAssert",
|
||||
// func
|
||||
"getFuncPtr",
|
||||
}
|
||||
|
||||
// makeDefs generates runtimetypes.go and writes it out after formatting it.
|
||||
func makeDefs() error {
|
||||
// Load the runtime package.
|
||||
pkgs, err := packages.Load(&packages.Config{
|
||||
Mode: packages.NeedSyntax,
|
||||
BuildFlags: []string{"-tags=gc.extalloc"},
|
||||
}, "../src/runtime")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(pkgs) != 1 {
|
||||
return fmt.Errorf("expected 1 package, got %d", len(pkgs))
|
||||
}
|
||||
runtimePkg := pkgs[0]
|
||||
if len(runtimePkg.Errors) != 0 {
|
||||
return runtimePkg.Errors[0]
|
||||
}
|
||||
|
||||
// Start creating the new Go file.
|
||||
buf := &bytes.Buffer{}
|
||||
buf.WriteString(`// Autogenerated by mkruntimetypes.go, DO NOT EDIT.
|
||||
|
||||
package compiler
|
||||
|
||||
// This file contains definitions for runtime types and functions, so that the
|
||||
// runtime package can be compiled independently of other packages.
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// getRuntimeType constructs a new runtime type with the given name. The types
|
||||
// constructed here must match the types in the runtime package.
|
||||
func (c *compilerContext) getRuntimeType(name string) types.Type {
|
||||
if c.program != nil {
|
||||
return c.program.ImportedPackage("runtime").Type(name).Type()
|
||||
}
|
||||
if typ, ok := c.runtimeTypes[name]; ok {
|
||||
// This type was already created.
|
||||
return typ
|
||||
}
|
||||
|
||||
typeName := types.NewTypeName(token.NoPos, c.runtimePkg, name, nil)
|
||||
named := types.NewNamed(typeName, nil, nil)
|
||||
|
||||
// Make sure recursive types are only defined once.
|
||||
c.runtimeTypes[name] = named
|
||||
|
||||
var fieldTypes []types.Type
|
||||
switch name {
|
||||
`)
|
||||
err = makeTypeDefs(buf, runtimePkg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf.WriteString(` default:
|
||||
panic("could not find runtime type: runtime." + name)
|
||||
}
|
||||
|
||||
// Create the named struct type.
|
||||
var fields []*types.Var
|
||||
for i, t := range fieldTypes {
|
||||
// Field name doesn't matter: this type is only used to create a LLVM
|
||||
// struct type which don't have field names.
|
||||
fields = append(fields, types.NewField(token.NoPos, nil, "field"+strconv.Itoa(i), t, false))
|
||||
}
|
||||
named.SetUnderlying(types.NewStruct(fields, nil))
|
||||
return named
|
||||
}
|
||||
|
||||
// getRuntimeFuncType constructs a new runtime function signature with the given
|
||||
// name. The function signatures constructed here must match the functions in
|
||||
// the runtime package.
|
||||
func (c *compilerContext) getRuntimeFuncType(name string) *types.Signature {
|
||||
var params []*types.Var
|
||||
addParam := func(name string, typ types.Type) {
|
||||
params = append(params, types.NewParam(token.NoPos, c.runtimePkg, name, typ))
|
||||
}
|
||||
var results []*types.Var
|
||||
addResult := func(typ types.Type) {
|
||||
results = append(results, types.NewParam(token.NoPos, c.runtimePkg, "", typ))
|
||||
}
|
||||
switch name {
|
||||
`)
|
||||
|
||||
err = makeFuncDefs(buf, runtimePkg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf.WriteString(` default:
|
||||
panic("unknown runtime call: runtime." + name)
|
||||
}
|
||||
return types.NewSignature(nil, types.NewTuple(params...), types.NewTuple(results...), false)
|
||||
}
|
||||
`)
|
||||
|
||||
source, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
// Fallback (useful for investigating errors).
|
||||
source = buf.Bytes()
|
||||
}
|
||||
err2 := ioutil.WriteFile("runtimetypes.go", source, 0666)
|
||||
if err2 != nil {
|
||||
return err2 // error from ioutil.WriteFile
|
||||
}
|
||||
return err // error from format.Source (if any)
|
||||
}
|
||||
|
||||
// makeTypeDefs generates the switch body of the getRuntimeType function.
|
||||
func makeTypeDefs(w io.Writer, runtimePkg *packages.Package) error {
|
||||
typeSpecs := map[string]*ast.TypeSpec{}
|
||||
for _, file := range runtimePkg.Syntax {
|
||||
for _, decl := range file.Decls {
|
||||
switch decl := decl.(type) {
|
||||
case *ast.GenDecl:
|
||||
if decl.Tok != token.TYPE {
|
||||
continue
|
||||
}
|
||||
for _, spec := range decl.Specs {
|
||||
typeSpec := spec.(*ast.TypeSpec)
|
||||
typeSpecs[typeSpec.Name.Name] = typeSpec
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range runtimeTypes {
|
||||
typeSpec := typeSpecs[name]
|
||||
if typeSpec == nil {
|
||||
return fmt.Errorf("could not find type: %s", name)
|
||||
}
|
||||
fmt.Fprintf(w, "\tcase %#v:\n", typeSpec.Name.Name)
|
||||
if name == "channelBlockedList" {
|
||||
fmt.Fprintf(w, "\t\ttaskType := types.NewNamed(types.NewTypeName(token.NoPos, c.taskPkg, \"Task\", nil), nil, nil)\n")
|
||||
}
|
||||
fmt.Fprintf(w, "\t\tfieldTypes = []types.Type{\n")
|
||||
for _, field := range typeSpec.Type.(*ast.StructType).Fields.List {
|
||||
fieldType := getTypeFromExpr(field.Type, typeSpec.Name.Name)
|
||||
for _, ident := range field.Names {
|
||||
fmt.Fprintf(w, "\t\t\t%s, // %s\n", fieldType, ident.Name)
|
||||
}
|
||||
}
|
||||
fmt.Fprintf(w, "\t\t}\n")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// makeFuncDefs generates the switch body of the getRuntimeFuncType function.
|
||||
func makeFuncDefs(w io.Writer, runtimePkg *packages.Package) error {
|
||||
functions := map[string]*ast.FuncDecl{}
|
||||
for _, file := range runtimePkg.Syntax {
|
||||
for _, decl := range file.Decls {
|
||||
switch decl := decl.(type) {
|
||||
case *ast.FuncDecl:
|
||||
functions[decl.Name.Name] = decl
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, name := range runtimeCalls {
|
||||
decl := functions[name]
|
||||
if decl == nil {
|
||||
return fmt.Errorf("could not find function: %s", name)
|
||||
}
|
||||
fmt.Fprintf(w, "\tcase %#v:\n", decl.Name.Name)
|
||||
for _, field := range decl.Type.Params.List {
|
||||
typeString := getTypeFromExpr(field.Type, "")
|
||||
for _, name := range field.Names {
|
||||
fmt.Fprintf(w, "\t\taddParam(%#v, %s)\n", name.Name, typeString)
|
||||
}
|
||||
}
|
||||
if decl.Type.Results != nil {
|
||||
for _, field := range decl.Type.Results.List {
|
||||
typeString := getTypeFromExpr(field.Type, "")
|
||||
for range field.Names {
|
||||
fmt.Fprintf(w, "\t\taddResult(%s)\n", typeString)
|
||||
}
|
||||
if len(field.Names) == 0 {
|
||||
fmt.Fprintf(w, "\t\taddResult(%s)\n", typeString)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// getTypeFromExpr returns a string which is a piece of Go code that constructs
|
||||
// the type (as given in ast.Expr) using the go/types package.
|
||||
func getTypeFromExpr(typ ast.Expr, currentTypeName string) string {
|
||||
switch typ := typ.(type) {
|
||||
case *ast.Ident:
|
||||
if typ.Name == currentTypeName {
|
||||
// Assume a global named "named" which refers to the currently
|
||||
// created named type.
|
||||
return "named"
|
||||
}
|
||||
switch typ.Name {
|
||||
case "bool", "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "float32", "float64", "complex64", "complex128", "string", "byte", "rune":
|
||||
// Built-in types.
|
||||
return fmt.Sprintf("types.Typ[types.%s]", strings.Title(typ.Name))
|
||||
case "chanState":
|
||||
// runtime.chanState is a named type, but that doesn't matter when
|
||||
// generating LLVM IR.
|
||||
return fmt.Sprintf("types.Typ[types.Uint8]")
|
||||
default:
|
||||
// Assume that we can simply get the type recursively.
|
||||
return fmt.Sprintf("c.getRuntimeType(%#v)", typ.Name)
|
||||
}
|
||||
case *ast.StarExpr:
|
||||
return fmt.Sprintf("types.NewPointer(%s)", getTypeFromExpr(typ.X, currentTypeName))
|
||||
case *ast.InterfaceType:
|
||||
if len(typ.Methods.List) != 0 {
|
||||
// Unimplemented: interfaces with methods.
|
||||
return "interface{?}"
|
||||
}
|
||||
return "types.NewInterfaceType(nil, nil)"
|
||||
case *ast.ArrayType:
|
||||
// Slices and arrays. Assume the array length is a numeric constant and
|
||||
// not a Go named constant for example.
|
||||
elementType := getTypeFromExpr(typ.Elt, currentTypeName)
|
||||
if typ.Len == nil {
|
||||
return fmt.Sprintf("types.NewSlice(%s)", elementType)
|
||||
}
|
||||
length := typ.Len.(*ast.BasicLit).Value
|
||||
return fmt.Sprintf("types.NewArray(%s, %s)", elementType, length)
|
||||
case *ast.SelectorExpr:
|
||||
s := typ.X.(*ast.Ident).Name + "." + typ.Sel.Name
|
||||
switch s {
|
||||
case "unsafe.Pointer":
|
||||
return "types.Typ[types.UnsafePointer]"
|
||||
case "task.Task":
|
||||
// Assume there is a variable taskType which refers to the task.Task
|
||||
// structure.
|
||||
return "taskType"
|
||||
default:
|
||||
return fmt.Sprintf("<unknown %s>", s)
|
||||
}
|
||||
case *ast.StructType:
|
||||
// Inline struct type.
|
||||
var fields string
|
||||
for _, field := range typ.Fields.List {
|
||||
fieldType := getTypeFromExpr(field.Type, currentTypeName)
|
||||
for _, ident := range field.Names {
|
||||
fields += fmt.Sprintf("\t\t\ttypes.NewField(token.NoPos, nil, %#v, %s, false),\n", ident.Name, fieldType)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("types.NewStruct([]*types.Var{\n%s\t\t}, nil)", fields)
|
||||
default:
|
||||
// Dump the raw typ value, for debugging.
|
||||
return fmt.Sprintf("%#v", typ)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
err := makeDefs()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "could not create defs:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,377 @@
|
||||
// Autogenerated by mkruntimetypes.go, DO NOT EDIT.
|
||||
|
||||
package compiler
|
||||
|
||||
// This file contains definitions for runtime types and functions, so that the
|
||||
// runtime package can be compiled independently of other packages.
|
||||
|
||||
import (
|
||||
"go/token"
|
||||
"go/types"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// getRuntimeType constructs a new runtime type with the given name. The types
|
||||
// constructed here must match the types in the runtime package.
|
||||
func (c *compilerContext) getRuntimeType(name string) types.Type {
|
||||
if c.program != nil {
|
||||
return c.program.ImportedPackage("runtime").Type(name).Type()
|
||||
}
|
||||
if typ, ok := c.runtimeTypes[name]; ok {
|
||||
// This type was already created.
|
||||
return typ
|
||||
}
|
||||
|
||||
typeName := types.NewTypeName(token.NoPos, c.runtimePkg, name, nil)
|
||||
named := types.NewNamed(typeName, nil, nil)
|
||||
|
||||
// Make sure recursive types are only defined once.
|
||||
c.runtimeTypes[name] = named
|
||||
|
||||
var fieldTypes []types.Type
|
||||
switch name {
|
||||
case "_defer":
|
||||
fieldTypes = []types.Type{
|
||||
types.Typ[types.Uintptr], // callback
|
||||
types.NewPointer(named), // next
|
||||
}
|
||||
case "_string":
|
||||
fieldTypes = []types.Type{
|
||||
types.NewPointer(types.Typ[types.Byte]), // ptr
|
||||
types.Typ[types.Uintptr], // length
|
||||
}
|
||||
case "stringIterator":
|
||||
fieldTypes = []types.Type{
|
||||
types.Typ[types.Uintptr], // byteindex
|
||||
}
|
||||
case "hashmap":
|
||||
fieldTypes = []types.Type{
|
||||
types.NewPointer(named), // next
|
||||
types.Typ[types.UnsafePointer], // buckets
|
||||
types.Typ[types.Uintptr], // count
|
||||
types.Typ[types.Uint8], // keySize
|
||||
types.Typ[types.Uint8], // valueSize
|
||||
types.Typ[types.Uint8], // bucketBits
|
||||
}
|
||||
case "hashmapBucket":
|
||||
fieldTypes = []types.Type{
|
||||
types.NewArray(types.Typ[types.Uint8], 8), // tophash
|
||||
types.NewPointer(named), // next
|
||||
}
|
||||
case "hashmapIterator":
|
||||
fieldTypes = []types.Type{
|
||||
types.Typ[types.Uintptr], // bucketNumber
|
||||
types.NewPointer(c.getRuntimeType("hashmapBucket")), // bucket
|
||||
types.Typ[types.Uint8], // bucketIndex
|
||||
}
|
||||
case "channel":
|
||||
fieldTypes = []types.Type{
|
||||
types.Typ[types.Uintptr], // elementSize
|
||||
types.Typ[types.Uintptr], // bufSize
|
||||
types.Typ[types.Uint8], // state
|
||||
types.NewPointer(c.getRuntimeType("channelBlockedList")), // blocked
|
||||
types.Typ[types.Uintptr], // bufHead
|
||||
types.Typ[types.Uintptr], // bufTail
|
||||
types.Typ[types.Uintptr], // bufUsed
|
||||
types.Typ[types.UnsafePointer], // buf
|
||||
}
|
||||
case "channelBlockedList":
|
||||
taskType := types.NewNamed(types.NewTypeName(token.NoPos, c.taskPkg, "Task", nil), nil, nil)
|
||||
fieldTypes = []types.Type{
|
||||
types.NewPointer(named), // next
|
||||
types.NewPointer(taskType), // t
|
||||
types.NewPointer(c.getRuntimeType("chanSelectState")), // s
|
||||
types.NewSlice(named), // allSelectOps
|
||||
}
|
||||
case "chanSelectState":
|
||||
fieldTypes = []types.Type{
|
||||
types.NewPointer(c.getRuntimeType("channel")), // ch
|
||||
types.Typ[types.UnsafePointer], // value
|
||||
}
|
||||
case "_interface":
|
||||
fieldTypes = []types.Type{
|
||||
types.Typ[types.Uintptr], // typecode
|
||||
types.Typ[types.UnsafePointer], // value
|
||||
}
|
||||
case "interfaceMethodInfo":
|
||||
fieldTypes = []types.Type{
|
||||
types.NewPointer(types.Typ[types.Uint8]), // signature
|
||||
types.Typ[types.Uintptr], // funcptr
|
||||
}
|
||||
case "typecodeID":
|
||||
fieldTypes = []types.Type{
|
||||
types.NewPointer(named), // references
|
||||
types.Typ[types.Uintptr], // length
|
||||
}
|
||||
case "structField":
|
||||
fieldTypes = []types.Type{
|
||||
types.NewPointer(c.getRuntimeType("typecodeID")), // typecode
|
||||
types.NewPointer(types.Typ[types.Uint8]), // name
|
||||
types.NewPointer(types.Typ[types.Uint8]), // tag
|
||||
types.Typ[types.Bool], // embedded
|
||||
}
|
||||
case "typeInInterface":
|
||||
fieldTypes = []types.Type{
|
||||
types.NewPointer(c.getRuntimeType("typecodeID")), // typecode
|
||||
types.NewPointer(c.getRuntimeType("interfaceMethodInfo")), // methodSet
|
||||
}
|
||||
case "funcValue":
|
||||
fieldTypes = []types.Type{
|
||||
types.Typ[types.UnsafePointer], // context
|
||||
types.Typ[types.Uintptr], // id
|
||||
}
|
||||
case "funcValueWithSignature":
|
||||
fieldTypes = []types.Type{
|
||||
types.Typ[types.Uintptr], // funcPtr
|
||||
types.NewPointer(c.getRuntimeType("typecodeID")), // signature
|
||||
}
|
||||
default:
|
||||
panic("could not find runtime type: runtime." + name)
|
||||
}
|
||||
|
||||
// Create the named struct type.
|
||||
var fields []*types.Var
|
||||
for i, t := range fieldTypes {
|
||||
// Field name doesn't matter: this type is only used to create a LLVM
|
||||
// struct type which don't have field names.
|
||||
fields = append(fields, types.NewField(token.NoPos, nil, "field"+strconv.Itoa(i), t, false))
|
||||
}
|
||||
named.SetUnderlying(types.NewStruct(fields, nil))
|
||||
return named
|
||||
}
|
||||
|
||||
// getRuntimeFuncType constructs a new runtime function signature with the given
|
||||
// name. The function signatures constructed here must match the functions in
|
||||
// the runtime package.
|
||||
func (c *compilerContext) getRuntimeFuncType(name string) *types.Signature {
|
||||
var params []*types.Var
|
||||
addParam := func(name string, typ types.Type) {
|
||||
params = append(params, types.NewParam(token.NoPos, c.runtimePkg, name, typ))
|
||||
}
|
||||
var results []*types.Var
|
||||
addResult := func(typ types.Type) {
|
||||
results = append(results, types.NewParam(token.NoPos, c.runtimePkg, "", typ))
|
||||
}
|
||||
switch name {
|
||||
case "_panic":
|
||||
addParam("message", types.NewInterfaceType(nil, nil))
|
||||
case "_recover":
|
||||
addResult(types.NewInterfaceType(nil, nil))
|
||||
case "nilPanic":
|
||||
case "lookupPanic":
|
||||
case "slicePanic":
|
||||
case "chanMakePanic":
|
||||
case "negativeShiftPanic":
|
||||
case "stringEqual":
|
||||
addParam("x", types.Typ[types.String])
|
||||
addParam("y", types.Typ[types.String])
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "stringLess":
|
||||
addParam("x", types.Typ[types.String])
|
||||
addParam("y", types.Typ[types.String])
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "stringConcat":
|
||||
addParam("x", c.getRuntimeType("_string"))
|
||||
addParam("y", c.getRuntimeType("_string"))
|
||||
addResult(c.getRuntimeType("_string"))
|
||||
case "stringFromBytes":
|
||||
addParam("x", types.NewStruct([]*types.Var{
|
||||
types.NewField(token.NoPos, nil, "ptr", types.NewPointer(types.Typ[types.Byte]), false),
|
||||
types.NewField(token.NoPos, nil, "len", types.Typ[types.Uintptr], false),
|
||||
types.NewField(token.NoPos, nil, "cap", types.Typ[types.Uintptr], false),
|
||||
}, nil))
|
||||
addResult(c.getRuntimeType("_string"))
|
||||
case "stringToBytes":
|
||||
addParam("x", c.getRuntimeType("_string"))
|
||||
addResult(types.NewStruct([]*types.Var{
|
||||
types.NewField(token.NoPos, nil, "ptr", types.NewPointer(types.Typ[types.Byte]), false),
|
||||
types.NewField(token.NoPos, nil, "len", types.Typ[types.Uintptr], false),
|
||||
types.NewField(token.NoPos, nil, "cap", types.Typ[types.Uintptr], false),
|
||||
}, nil))
|
||||
case "stringFromRunes":
|
||||
addParam("runeSlice", types.NewSlice(types.Typ[types.Rune]))
|
||||
addResult(c.getRuntimeType("_string"))
|
||||
case "stringToRunes":
|
||||
addParam("s", types.Typ[types.String])
|
||||
addResult(types.NewSlice(types.Typ[types.Rune]))
|
||||
case "stringFromUnicode":
|
||||
addParam("x", types.Typ[types.Rune])
|
||||
addResult(c.getRuntimeType("_string"))
|
||||
case "stringNext":
|
||||
addParam("s", types.Typ[types.String])
|
||||
addParam("it", types.NewPointer(c.getRuntimeType("stringIterator")))
|
||||
addResult(types.Typ[types.Bool])
|
||||
addResult(types.Typ[types.Int])
|
||||
addResult(types.Typ[types.Rune])
|
||||
case "complex64div":
|
||||
addParam("n", types.Typ[types.Complex64])
|
||||
addParam("m", types.Typ[types.Complex64])
|
||||
addResult(types.Typ[types.Complex64])
|
||||
case "complex128div":
|
||||
addParam("n", types.Typ[types.Complex128])
|
||||
addParam("m", types.Typ[types.Complex128])
|
||||
addResult(types.Typ[types.Complex128])
|
||||
case "sliceAppend":
|
||||
addParam("srcBuf", types.Typ[types.UnsafePointer])
|
||||
addParam("elemsBuf", types.Typ[types.UnsafePointer])
|
||||
addParam("srcLen", types.Typ[types.Uintptr])
|
||||
addParam("srcCap", types.Typ[types.Uintptr])
|
||||
addParam("elemsLen", types.Typ[types.Uintptr])
|
||||
addParam("elemSize", types.Typ[types.Uintptr])
|
||||
addResult(types.Typ[types.UnsafePointer])
|
||||
addResult(types.Typ[types.Uintptr])
|
||||
addResult(types.Typ[types.Uintptr])
|
||||
case "sliceCopy":
|
||||
addParam("dst", types.Typ[types.UnsafePointer])
|
||||
addParam("src", types.Typ[types.UnsafePointer])
|
||||
addParam("dstLen", types.Typ[types.Uintptr])
|
||||
addParam("srcLen", types.Typ[types.Uintptr])
|
||||
addParam("elemSize", types.Typ[types.Uintptr])
|
||||
addResult(types.Typ[types.Int])
|
||||
case "alloc":
|
||||
addParam("size", types.Typ[types.Uintptr])
|
||||
addResult(types.Typ[types.UnsafePointer])
|
||||
case "trackPointer":
|
||||
addParam("ptr", types.Typ[types.UnsafePointer])
|
||||
case "printbool":
|
||||
addParam("b", types.Typ[types.Bool])
|
||||
case "printint8":
|
||||
addParam("n", types.Typ[types.Int8])
|
||||
case "printuint8":
|
||||
addParam("n", types.Typ[types.Uint8])
|
||||
case "printint16":
|
||||
addParam("n", types.Typ[types.Int16])
|
||||
case "printuint16":
|
||||
addParam("n", types.Typ[types.Uint16])
|
||||
case "printint32":
|
||||
addParam("n", types.Typ[types.Int32])
|
||||
case "printuint32":
|
||||
addParam("n", types.Typ[types.Uint32])
|
||||
case "printint64":
|
||||
addParam("n", types.Typ[types.Int64])
|
||||
case "printuint64":
|
||||
addParam("n", types.Typ[types.Uint64])
|
||||
case "printfloat32":
|
||||
addParam("v", types.Typ[types.Float32])
|
||||
case "printfloat64":
|
||||
addParam("v", types.Typ[types.Float64])
|
||||
case "printcomplex64":
|
||||
addParam("c", types.Typ[types.Complex64])
|
||||
case "printcomplex128":
|
||||
addParam("c", types.Typ[types.Complex128])
|
||||
case "printstring":
|
||||
addParam("s", types.Typ[types.String])
|
||||
case "printspace":
|
||||
case "printnl":
|
||||
case "printptr":
|
||||
addParam("ptr", types.Typ[types.Uintptr])
|
||||
case "printmap":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
case "printitf":
|
||||
addParam("msg", types.NewInterfaceType(nil, nil))
|
||||
case "hashmapMake":
|
||||
addParam("keySize", types.Typ[types.Uint8])
|
||||
addParam("valueSize", types.Typ[types.Uint8])
|
||||
addParam("sizeHint", types.Typ[types.Uintptr])
|
||||
addResult(types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
case "hashmapLen":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
addResult(types.Typ[types.Int])
|
||||
case "hashmapNext":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
addParam("it", types.NewPointer(c.getRuntimeType("hashmapIterator")))
|
||||
addParam("key", types.Typ[types.UnsafePointer])
|
||||
addParam("value", types.Typ[types.UnsafePointer])
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "hashmapStringGet":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
addParam("key", types.Typ[types.String])
|
||||
addParam("value", types.Typ[types.UnsafePointer])
|
||||
addParam("valueSize", types.Typ[types.Uintptr])
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "hashmapStringSet":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
addParam("key", types.Typ[types.String])
|
||||
addParam("value", types.Typ[types.UnsafePointer])
|
||||
case "hashmapStringDelete":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
addParam("key", types.Typ[types.String])
|
||||
case "hashmapInterfaceGet":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
addParam("key", types.NewInterfaceType(nil, nil))
|
||||
addParam("value", types.Typ[types.UnsafePointer])
|
||||
addParam("valueSize", types.Typ[types.Uintptr])
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "hashmapInterfaceSet":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
addParam("key", types.NewInterfaceType(nil, nil))
|
||||
addParam("value", types.Typ[types.UnsafePointer])
|
||||
case "hashmapInterfaceDelete":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
addParam("key", types.NewInterfaceType(nil, nil))
|
||||
case "hashmapBinaryGet":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
addParam("key", types.Typ[types.UnsafePointer])
|
||||
addParam("value", types.Typ[types.UnsafePointer])
|
||||
addParam("valueSize", types.Typ[types.Uintptr])
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "hashmapBinarySet":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
addParam("key", types.Typ[types.UnsafePointer])
|
||||
addParam("value", types.Typ[types.UnsafePointer])
|
||||
case "hashmapBinaryDelete":
|
||||
addParam("m", types.NewPointer(c.getRuntimeType("hashmap")))
|
||||
addParam("key", types.Typ[types.UnsafePointer])
|
||||
case "tryChanSelect":
|
||||
addParam("recvbuf", types.Typ[types.UnsafePointer])
|
||||
addParam("states", types.NewSlice(c.getRuntimeType("chanSelectState")))
|
||||
addResult(types.Typ[types.Uintptr])
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "chanMake":
|
||||
addParam("elementSize", types.Typ[types.Uintptr])
|
||||
addParam("bufSize", types.Typ[types.Uintptr])
|
||||
addResult(types.NewPointer(c.getRuntimeType("channel")))
|
||||
case "chanSend":
|
||||
addParam("ch", types.NewPointer(c.getRuntimeType("channel")))
|
||||
addParam("value", types.Typ[types.UnsafePointer])
|
||||
case "chanRecv":
|
||||
addParam("ch", types.NewPointer(c.getRuntimeType("channel")))
|
||||
addParam("value", types.Typ[types.UnsafePointer])
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "chanClose":
|
||||
addParam("ch", types.NewPointer(c.getRuntimeType("channel")))
|
||||
case "chanSelect":
|
||||
addParam("recvbuf", types.Typ[types.UnsafePointer])
|
||||
addParam("states", types.NewSlice(c.getRuntimeType("chanSelectState")))
|
||||
addParam("ops", types.NewSlice(c.getRuntimeType("channelBlockedList")))
|
||||
addResult(types.Typ[types.Uintptr])
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "deadlock":
|
||||
case "interfaceEqual":
|
||||
addParam("x", types.NewInterfaceType(nil, nil))
|
||||
addParam("y", types.NewInterfaceType(nil, nil))
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "interfaceImplements":
|
||||
addParam("typecode", types.Typ[types.Uintptr])
|
||||
addParam("interfaceMethodSet", types.NewPointer(types.NewPointer(types.Typ[types.Uint8])))
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "interfaceMethod":
|
||||
addParam("typecode", types.Typ[types.Uintptr])
|
||||
addParam("interfaceMethodSet", types.NewPointer(types.NewPointer(types.Typ[types.Uint8])))
|
||||
addParam("signature", types.NewPointer(types.Typ[types.Uint8]))
|
||||
addResult(types.Typ[types.Uintptr])
|
||||
case "typeAssert":
|
||||
addParam("actualType", types.Typ[types.Uintptr])
|
||||
addParam("assertedType", types.NewPointer(c.getRuntimeType("typecodeID")))
|
||||
addResult(types.Typ[types.Bool])
|
||||
case "interfaceTypeAssert":
|
||||
addParam("ok", types.Typ[types.Bool])
|
||||
case "getFuncPtr":
|
||||
addParam("val", c.getRuntimeType("funcValue"))
|
||||
addParam("signature", types.NewPointer(c.getRuntimeType("typecodeID")))
|
||||
addResult(types.Typ[types.Uintptr])
|
||||
default:
|
||||
panic("unknown runtime call: runtime." + name)
|
||||
}
|
||||
return types.NewSignature(nil, types.NewTuple(params...), types.NewTuple(results...), false)
|
||||
}
|
||||
+223
-1
@@ -15,6 +15,208 @@ import (
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
type inlineType int
|
||||
|
||||
// How much to inline.
|
||||
const (
|
||||
// Default behavior. The compiler decides for itself whether any given
|
||||
// function will be inlined. Whether any function is inlined depends on the
|
||||
// optimization level.
|
||||
inlineDefault inlineType = iota
|
||||
|
||||
// Inline hint, just like the C inline keyword (signalled using
|
||||
// //go:inline). The compiler will be more likely to inline this function,
|
||||
// but it is not a guarantee.
|
||||
inlineHint
|
||||
|
||||
// Don't inline, just like the GCC noinline attribute. Signalled using
|
||||
// //go:noinline.
|
||||
inlineNone
|
||||
)
|
||||
|
||||
// functionInfo contains some information about a function or method. In
|
||||
// particular, it contains information obtained from pragmas.
|
||||
//
|
||||
// The linkName value contains a valid link name, even though //go:linkname is
|
||||
// not present.
|
||||
type functionInfo struct {
|
||||
linkName string // go:linkname, go:export
|
||||
module string // go:wasm-module
|
||||
exported bool // go:export
|
||||
nobounds bool // go:nobounds
|
||||
inline inlineType // go:inline
|
||||
}
|
||||
|
||||
// getFunction returns the LLVM function for the given *ssa.Function, creating
|
||||
// it if needed. It can later be filled with compilerContext.createFunction().
|
||||
func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
|
||||
info := c.getFunctionInfo(fn)
|
||||
return c.getFunctionRaw(fn.Signature, info)
|
||||
}
|
||||
|
||||
func (c *compilerContext) getFunctionRaw(sig *types.Signature, info functionInfo) llvm.Value {
|
||||
llvmFn := c.mod.NamedFunction(info.linkName)
|
||||
if !llvmFn.IsNil() {
|
||||
return llvmFn
|
||||
}
|
||||
|
||||
var retType llvm.Type
|
||||
if sig.Results() == nil {
|
||||
retType = c.ctx.VoidType()
|
||||
} else if sig.Results().Len() == 1 {
|
||||
retType = c.getLLVMType(sig.Results().At(0).Type())
|
||||
} else {
|
||||
results := make([]llvm.Type, 0, sig.Results().Len())
|
||||
for i := 0; i < sig.Results().Len(); i++ {
|
||||
results = append(results, c.getLLVMType(sig.Results().At(i).Type()))
|
||||
}
|
||||
retType = c.ctx.StructType(results, false)
|
||||
}
|
||||
|
||||
var paramInfos []paramInfo
|
||||
params := []*types.Var{}
|
||||
if sig.Recv() != nil {
|
||||
params = append(params, sig.Recv())
|
||||
}
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
params = append(params, sig.Params().At(i))
|
||||
}
|
||||
for _, param := range params {
|
||||
paramType := c.getLLVMType(param.Type())
|
||||
paramFragmentInfos := expandFormalParamType(paramType, param.Name(), param.Type())
|
||||
paramInfos = append(paramInfos, paramFragmentInfos...)
|
||||
}
|
||||
|
||||
// Add an extra parameter as the function context. This context is used in
|
||||
// closures and bound methods, but should be optimized away when not used.
|
||||
if !info.exported {
|
||||
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "context", flags: 0})
|
||||
paramInfos = append(paramInfos, paramInfo{llvmType: c.i8ptrType, name: "parentHandle", flags: 0})
|
||||
}
|
||||
|
||||
var paramTypes []llvm.Type
|
||||
for _, info := range paramInfos {
|
||||
paramTypes = append(paramTypes, info.llvmType)
|
||||
}
|
||||
|
||||
fnType := llvm.FunctionType(retType, paramTypes, false)
|
||||
llvmFn = llvm.AddFunction(c.mod, info.linkName, fnType)
|
||||
|
||||
dereferenceableOrNullKind := llvm.AttributeKindID("dereferenceable_or_null")
|
||||
for i, info := range paramInfos {
|
||||
if info.flags¶mIsDeferenceableOrNull == 0 {
|
||||
continue
|
||||
}
|
||||
if info.llvmType.TypeKind() == llvm.PointerTypeKind {
|
||||
el := info.llvmType.ElementType()
|
||||
size := c.targetData.TypeAllocSize(el)
|
||||
if size == 0 {
|
||||
// dereferenceable_or_null(0) appears to be illegal in LLVM.
|
||||
continue
|
||||
}
|
||||
dereferenceableOrNull := c.ctx.CreateEnumAttribute(dereferenceableOrNullKind, size)
|
||||
llvmFn.AddAttributeAtIndex(i+1, dereferenceableOrNull)
|
||||
}
|
||||
}
|
||||
|
||||
// External/exported functions may not retain pointer values.
|
||||
// https://golang.org/cmd/cgo/#hdr-Passing_pointers
|
||||
if info.exported {
|
||||
// Set the wasm-import-module attribute if the function's module is set.
|
||||
if info.module != "" {
|
||||
wasmImportModuleAttr := c.ctx.CreateStringAttribute("wasm-import-module", info.module)
|
||||
llvmFn.AddFunctionAttr(wasmImportModuleAttr)
|
||||
}
|
||||
nocaptureKind := llvm.AttributeKindID("nocapture")
|
||||
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
|
||||
for i, typ := range paramTypes {
|
||||
if typ.TypeKind() == llvm.PointerTypeKind {
|
||||
llvmFn.AddAttributeAtIndex(i+1, nocapture)
|
||||
}
|
||||
}
|
||||
}
|
||||
return llvmFn
|
||||
}
|
||||
|
||||
// getFunctionInfo returns information about a function that is not directly
|
||||
// present in *ssa.Function, such as the link name and whether it should be
|
||||
// exported.
|
||||
func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
|
||||
info := functionInfo{}
|
||||
if strings.HasPrefix(f.Name(), "C.") {
|
||||
// Created by CGo: such a name cannot be created by regular C code.
|
||||
info.linkName = f.Name()[2:]
|
||||
info.exported = true
|
||||
} else {
|
||||
// Pick the default linkName.
|
||||
info.linkName = f.RelString(nil)
|
||||
// Check for //go: pragmas, which may change the link name (among
|
||||
// others).
|
||||
info.parsePragmas(f)
|
||||
}
|
||||
return info
|
||||
}
|
||||
|
||||
// parsePragmas is used by getFunctionInfo to parse function pragmas such as
|
||||
// //export or //go:noinline.
|
||||
func (info *functionInfo) parsePragmas(f *ssa.Function) {
|
||||
// Parse compiler directives in the preceding comments.
|
||||
if f.Syntax() == nil {
|
||||
return
|
||||
}
|
||||
if decl, ok := f.Syntax().(*ast.FuncDecl); ok && decl.Doc != nil {
|
||||
for _, comment := range decl.Doc.List {
|
||||
text := comment.Text
|
||||
if strings.HasPrefix(text, "//export ") {
|
||||
// Rewrite '//export' to '//go:export' for compatibility with
|
||||
// gc.
|
||||
text = "//go:" + text[2:]
|
||||
}
|
||||
if !strings.HasPrefix(text, "//go:") {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(text)
|
||||
switch parts[0] {
|
||||
case "//go:export":
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
info.linkName = parts[1]
|
||||
info.exported = true
|
||||
case "//go:wasm-module":
|
||||
// Alternative comment for setting the import module.
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
info.module = parts[1]
|
||||
case "//go:inline":
|
||||
info.inline = inlineHint
|
||||
case "//go:noinline":
|
||||
info.inline = inlineNone
|
||||
case "//go:linkname":
|
||||
if len(parts) != 3 || parts[1] != f.Name() {
|
||||
continue
|
||||
}
|
||||
// Only enable go:linkname when the package imports "unsafe".
|
||||
// This is a slightly looser requirement than what gc uses: gc
|
||||
// requires the file to import "unsafe", not the package as a
|
||||
// whole.
|
||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||
info.linkName = parts[2]
|
||||
}
|
||||
case "//go:nobounds":
|
||||
// Skip bounds checking in this function. Useful for some
|
||||
// runtime functions.
|
||||
// This is somewhat dangerous and thus only imported in packages
|
||||
// that import unsafe.
|
||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||
info.nobounds = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// globalInfo contains some information about a specific global. By default,
|
||||
// linkName is equal to .RelString(nil) on a global and extern is false, but for
|
||||
// some symbols this is different (due to //go:extern for example).
|
||||
@@ -86,7 +288,7 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
|
||||
// Add debug info.
|
||||
// TODO: this should be done for every global in the program, not just
|
||||
// the ones that are referenced from some code.
|
||||
pos := c.ir.Program.Fset.Position(g.Pos())
|
||||
pos := c.program.Fset.Position(g.Pos())
|
||||
diglobal := c.dibuilder.CreateGlobalVariableExpression(c.difiles[pos.Filename], llvm.DIGlobalVariableExpression{
|
||||
Name: g.RelString(nil),
|
||||
LinkageName: info.linkName,
|
||||
@@ -145,3 +347,23 @@ func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get all methods of a type.
|
||||
func getAllMethods(prog *ssa.Program, typ types.Type) []*types.Selection {
|
||||
ms := prog.MethodSets.MethodSet(typ)
|
||||
methods := make([]*types.Selection, ms.Len())
|
||||
for i := 0; i < ms.Len(); i++ {
|
||||
methods[i] = ms.At(i)
|
||||
}
|
||||
return methods
|
||||
}
|
||||
|
||||
// Return true if this package imports "unsafe", false otherwise.
|
||||
func hasUnsafeImport(pkg *types.Package) bool {
|
||||
for _, imp := range pkg.Imports() {
|
||||
if imp == types.Unsafe {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
func add(x, y int) int {
|
||||
return x + y
|
||||
}
|
||||
|
||||
func stringEqual(s string) bool {
|
||||
return s == "s"
|
||||
}
|
||||
|
||||
func closeChan(ch chan int) {
|
||||
close(ch)
|
||||
}
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "armv7m-none-eabi"
|
||||
|
||||
%runtime.channel = type { i32, i32, i8, %runtime.channelBlockedList*, i32, i32, i32, i8* }
|
||||
%runtime.channelBlockedList = type { %runtime.channelBlockedList*, %"internal/task.Task"*, %runtime.chanSelectState*, { %runtime.channelBlockedList*, i32, i32 } }
|
||||
%"internal/task.Task" = type opaque
|
||||
%runtime.chanSelectState = type { %runtime.channel*, i8* }
|
||||
%runtime._string = type { i8*, i32 }
|
||||
|
||||
@"main.stringEqual$string" = internal unnamed_addr constant [1 x i8] c"s"
|
||||
|
||||
define internal i32 @main.add(i32 %x, i32 %y, i8* %context, i8* %parentHandle) unnamed_addr {
|
||||
entry:
|
||||
%0 = add i32 %x, %y
|
||||
ret i32 %0
|
||||
}
|
||||
|
||||
define internal void @main.closeChan(%runtime.channel* dereferenceable_or_null(32) %ch, i8* %context, i8* %parentHandle) unnamed_addr {
|
||||
entry:
|
||||
call void @runtime.chanClose(%runtime.channel* %ch, i8* undef, i8* null)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @runtime.chanClose(%runtime.channel* dereferenceable_or_null(32), i8*, i8*)
|
||||
|
||||
define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal i1 @main.stringEqual(i8* %s.data, i32 %s.len, i8* %context, i8* %parentHandle) unnamed_addr {
|
||||
entry:
|
||||
%0 = insertvalue %runtime._string zeroinitializer, i8* %s.data, 0
|
||||
%1 = insertvalue %runtime._string %0, i32 %s.len, 1
|
||||
%2 = extractvalue %runtime._string %1, 0
|
||||
%3 = extractvalue %runtime._string %1, 1
|
||||
%4 = call i1 @runtime.stringEqual(i8* %2, i32 %3, i8* getelementptr inbounds ([1 x i8], [1 x i8]* @"main.stringEqual$string", i32 0, i32 0), i32 1, i8* undef, i8* null)
|
||||
ret i1 %4
|
||||
}
|
||||
|
||||
declare i1 @runtime.stringEqual(i8*, i32, i8*, i32, i8*, i8*)
|
||||
@@ -4,11 +4,10 @@ go 1.11
|
||||
|
||||
require (
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
||||
github.com/chromedp/cdproto v0.0.0-20200709115526-d1f6fc58448b
|
||||
github.com/chromedp/chromedp v0.5.4-0.20200303084119-2bb39134ab9e
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
|
||||
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46
|
||||
go.bug.st/serial v1.0.0
|
||||
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2
|
||||
tinygo.org/x/go-llvm v0.0.0-20201104183921-570e7a6841d9
|
||||
google.golang.org/appengine v1.4.0 // indirect
|
||||
tinygo.org/x/go-llvm v0.0.0-20200401165421-8d120882fc7a
|
||||
)
|
||||
|
||||
@@ -1,28 +1,13 @@
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
|
||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||
github.com/chromedp/cdproto v0.0.0-20200116234248-4da64dd111ac/go.mod h1:PfAWWKJqjlGFYJEidUM6aVIWPr0EpobeyVWEEmplX7g=
|
||||
github.com/chromedp/cdproto v0.0.0-20200709115526-d1f6fc58448b h1:LF+GRwyzxrO3MUzPvejv+yBup0lNG+/QdIRrkxOPseA=
|
||||
github.com/chromedp/cdproto v0.0.0-20200709115526-d1f6fc58448b/go.mod h1:E6LPWRdIJc11h/di5p0rwvRmUYbhGpBEH7ZbPfzDIOE=
|
||||
github.com/chromedp/chromedp v0.5.4-0.20200303084119-2bb39134ab9e h1:Hv0JVyHhbIXb9NiYQe4NsrfgrSofAp0q2FnhhJOXgi8=
|
||||
github.com/chromedp/chromedp v0.5.4-0.20200303084119-2bb39134ab9e/go.mod h1:vmQMRHFZrY3T+Jv51T0n87OK/i6bK+5P9a+Fg5jPwgQ=
|
||||
github.com/creack/goselect v0.1.1 h1:tiSSgKE1eJtxs1h/VgGQWuXUP0YS4CDIFMp6vaI1ls0=
|
||||
github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0=
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
|
||||
github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8=
|
||||
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.0.3 h1:ZOigqf7iBxkA4jdQ3am7ATzdlOFp9YzA6NmuvEEZc9g=
|
||||
github.com/gobwas/ws v1.0.3/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
|
||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
|
||||
github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08 h1:V0an7KRw92wmJysvFvtqtKMAPmvS5O0jtB0nYo6t+gs=
|
||||
github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08/go.mod h1:dFWs1zEqDjFtnBXsd1vPOZaLsESovai349994nHx3e0=
|
||||
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8=
|
||||
github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892 h1:6J+qramlHVLmiBOgRiBOnQkno8uprqG6YFFQTt6uYIw=
|
||||
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
||||
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46 h1:wXG2bA8fO7Vv7lLk2PihFMTqmbT173Tje39oKzQ50Mo=
|
||||
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
@@ -32,21 +17,43 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU=
|
||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef h1:ymc9FeDom3RIEA3coKokSllBB1hRcMT0tZ1W3Jf9Ids=
|
||||
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2 h1:0sfSpGSa544Fwnbot3Oxq/U6SXqjty6Jy/3wRhVS7ig=
|
||||
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
tinygo.org/x/go-llvm v0.0.0-20201104183921-570e7a6841d9 h1:l2kTQOhqEoeDTK3ckUnwReOQwMPUmURMIdjJbeAuDT4=
|
||||
tinygo.org/x/go-llvm v0.0.0-20201104183921-570e7a6841d9/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261 h1:rJS2Hga39YAnm7DE4qrPm6Dr/67EOojL0XPzvbEeBiw=
|
||||
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
tinygo.org/x/go-llvm v0.0.0-20190818154551-95bc4ffe1add h1:dFjMH1sLhYADg8UQm7DB56B7e+TfvAmWmEZLhyv3r/w=
|
||||
tinygo.org/x/go-llvm v0.0.0-20190818154551-95bc4ffe1add/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
tinygo.org/x/go-llvm v0.0.0-20191103182207-90b6e4bdc0b9 h1:d6rAX39a3C0pKrY5HcojEGyN8w9ocU0v7X28lC/TRKU=
|
||||
tinygo.org/x/go-llvm v0.0.0-20191103182207-90b6e4bdc0b9/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
tinygo.org/x/go-llvm v0.0.0-20191103200204-37e93e3f04e2 h1:Q5Hv3e5cLMGkiYwYgZL1Zrv6nb/EY+DJpRWrdO6ws6o=
|
||||
tinygo.org/x/go-llvm v0.0.0-20191103200204-37e93e3f04e2/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
tinygo.org/x/go-llvm v0.0.0-20191113125529-bad6d01809e8 h1:9Bfvso+tTVQg16UzOA614NaYA4x8vsRBNtd3eBrXwp0=
|
||||
tinygo.org/x/go-llvm v0.0.0-20191113125529-bad6d01809e8/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
tinygo.org/x/go-llvm v0.0.0-20191124211856-b2db3df3f257 h1:o8VDylrMN7gWemBMu8rEyuogKPhcLTdx5KrUAp9macc=
|
||||
tinygo.org/x/go-llvm v0.0.0-20191124211856-b2db3df3f257/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
tinygo.org/x/go-llvm v0.0.0-20191215173731-ad71f3d24aae h1:s8J5EyxCkHxXB08UI3gk9W9IS/ekizRvSX+PfZxnAB0=
|
||||
tinygo.org/x/go-llvm v0.0.0-20191215173731-ad71f3d24aae/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
tinygo.org/x/go-llvm v0.0.0-20200104190746-1ff21df33566 h1:a4y30bTf7U0zDA75v2PTL+XQ2OzJetj19gK8XwQpUNY=
|
||||
tinygo.org/x/go-llvm v0.0.0-20200104190746-1ff21df33566/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
tinygo.org/x/go-llvm v0.0.0-20200226165415-53522ab6713d h1:mtgZh/e8a3wxneQFuLXoQYO//1mvlki02yZ1JCwMKp4=
|
||||
tinygo.org/x/go-llvm v0.0.0-20200226165415-53522ab6713d/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
tinygo.org/x/go-llvm v0.0.0-20200401165421-8d120882fc7a h1:Ugje2Lxuv8CFncHzs5W+hWfJvPsM+W4K0zRvzFbLvoE=
|
||||
tinygo.org/x/go-llvm v0.0.0-20200401165421-8d120882fc7a/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
package goenv
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Version of TinyGo.
|
||||
// Update this value before release of new version of software.
|
||||
const Version = "0.16.0"
|
||||
|
||||
// GetGorootVersion returns the major and minor version for a given GOROOT path.
|
||||
// If the goroot cannot be determined, (0, 0) is returned.
|
||||
func GetGorootVersion(goroot string) (major, minor int, err error) {
|
||||
s, err := GorootVersionString(goroot)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
if s == "" || s[:2] != "go" {
|
||||
return 0, 0, errors.New("could not parse Go version: version does not start with 'go' prefix")
|
||||
}
|
||||
|
||||
parts := strings.Split(s[2:], ".")
|
||||
if len(parts) < 2 {
|
||||
return 0, 0, errors.New("could not parse Go version: version has less than two parts")
|
||||
}
|
||||
|
||||
// Ignore the errors, we don't really handle errors here anyway.
|
||||
var trailing string
|
||||
n, err := fmt.Sscanf(s, "go%d.%d%s", &major, &minor, &trailing)
|
||||
if n == 2 && err == io.EOF {
|
||||
// Means there were no trailing characters (i.e., not an alpha/beta)
|
||||
err = nil
|
||||
}
|
||||
if err != nil {
|
||||
return 0, 0, fmt.Errorf("failed to parse version: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// GorootVersionString returns the version string as reported by the Go
|
||||
// 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 := ioutil.ReadFile(filepath.Join(
|
||||
goroot, "src", "runtime", "internal", "sys", "zversion.go")); err == nil {
|
||||
|
||||
r := regexp.MustCompile("const TheVersion = `(.*)`")
|
||||
matches := r.FindSubmatch(data)
|
||||
if len(matches) != 2 {
|
||||
return "", errors.New("Invalid go version output:\n" + string(data))
|
||||
}
|
||||
|
||||
return string(matches[1]), nil
|
||||
|
||||
} else if data, err := ioutil.ReadFile(filepath.Join(goroot, "VERSION")); err == nil {
|
||||
return string(data), nil
|
||||
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
# Hooks for Docker Hub
|
||||
|
||||
Files in this directory are custom commands to be run during the different Docker Hub build phases.
|
||||
|
||||
See https://docs.docker.com/docker-hub/builds/advanced/#custom-build-phase-hooks
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Docker hub does a recursive clone, then checks the branch out,
|
||||
# so when a PR adds a submodule (or updates it), it fails.
|
||||
git submodule update --init
|
||||
+1
-3
@@ -47,12 +47,10 @@ func (e *Error) Error() string {
|
||||
// location of the instruction. The location information may not be complete as
|
||||
// it depends on debug information in the IR.
|
||||
func (e *evalPackage) errorAt(inst llvm.Value, err error) *Error {
|
||||
pos := getPosition(inst)
|
||||
return &Error{
|
||||
ImportPath: e.packagePath,
|
||||
Pos: pos,
|
||||
Pos: getPosition(inst),
|
||||
Err: err,
|
||||
Traceback: []ErrorLine{{pos, inst}},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
-38
@@ -95,11 +95,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||
if !operand.IsConstant() || inst.IsVolatile() || (!operand.Underlying.IsAConstantExpr().IsNil() && operand.Underlying.Opcode() == llvm.BitCast) {
|
||||
value = fr.builder.CreateLoad(operand.Value(), inst.Name())
|
||||
} else {
|
||||
var err error
|
||||
value, err = operand.Load()
|
||||
if err != nil {
|
||||
return nil, nil, fr.errorAt(inst, err)
|
||||
}
|
||||
value = operand.Load()
|
||||
}
|
||||
if value.Type() != inst.Type() {
|
||||
return nil, nil, fr.errorAt(inst, errors.New("interp: load: type does not match"))
|
||||
@@ -111,10 +107,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||
if inst.IsVolatile() {
|
||||
fr.builder.CreateStore(value.Value(), ptr.Value())
|
||||
} else {
|
||||
err := ptr.Store(value.Value())
|
||||
if err != nil {
|
||||
return nil, nil, fr.errorAt(inst, err)
|
||||
}
|
||||
ptr.Store(value.Value())
|
||||
}
|
||||
case !inst.IsAGetElementPtrInst().IsNil():
|
||||
value := fr.getLocal(inst.Operand(0))
|
||||
@@ -290,6 +283,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||
PkgName: fr.packagePath,
|
||||
KeySize: int(keySize),
|
||||
ValueSize: int(valueSize),
|
||||
MapType: inst.Type().ElementType(),
|
||||
}
|
||||
case callee.Name() == "runtime.hashmapStringSet":
|
||||
// set a string key in the map
|
||||
@@ -315,10 +309,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||
}
|
||||
// "key" is a Go string value, which in the TinyGo calling convention is split up
|
||||
// into separate pointer and length parameters.
|
||||
err := m.PutString(keyBuf, keyLen, valPtr)
|
||||
if err != nil {
|
||||
return nil, nil, fr.errorAt(inst, err)
|
||||
}
|
||||
m.PutString(keyBuf, keyLen, valPtr)
|
||||
case callee.Name() == "runtime.hashmapBinarySet":
|
||||
// set a binary (int etc.) key in the map
|
||||
keyBuf := fr.getLocal(inst.Operand(1)).(*LocalValue)
|
||||
@@ -339,24 +330,15 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||
fr.builder.CreateCall(callee, llvmParams, "")
|
||||
continue
|
||||
}
|
||||
err := m.PutBinary(keyBuf, valPtr)
|
||||
if err != nil {
|
||||
return nil, nil, fr.errorAt(inst, err)
|
||||
}
|
||||
m.PutBinary(keyBuf, valPtr)
|
||||
case callee.Name() == "runtime.stringConcat":
|
||||
// adding two strings together
|
||||
buf1Ptr := fr.getLocal(inst.Operand(0))
|
||||
buf1Len := fr.getLocal(inst.Operand(1))
|
||||
buf2Ptr := fr.getLocal(inst.Operand(2))
|
||||
buf2Len := fr.getLocal(inst.Operand(3))
|
||||
buf1, err := getStringBytes(buf1Ptr, buf1Len.Value())
|
||||
if err != nil {
|
||||
return nil, nil, fr.errorAt(inst, err)
|
||||
}
|
||||
buf2, err := getStringBytes(buf2Ptr, buf2Len.Value())
|
||||
if err != nil {
|
||||
return nil, nil, fr.errorAt(inst, err)
|
||||
}
|
||||
buf1 := getStringBytes(buf1Ptr, buf1Len.Value())
|
||||
buf2 := getStringBytes(buf2Ptr, buf2Len.Value())
|
||||
result := []byte(string(buf1) + string(buf2))
|
||||
vals := make([]llvm.Value, len(result))
|
||||
for i := range vals {
|
||||
@@ -369,7 +351,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||
global.SetLinkage(llvm.InternalLinkage)
|
||||
global.SetGlobalConstant(true)
|
||||
global.SetUnnamedAddr(true)
|
||||
stringType := fr.Mod.GetTypeByName("runtime._string")
|
||||
stringType := inst.Type()
|
||||
retPtr := llvm.ConstGEP(global, getLLVMIndices(fr.Mod.Context().Int32Type(), []uint32{0, 0}))
|
||||
retLen := llvm.ConstInt(stringType.StructElementTypes()[1], uint64(len(result)), false)
|
||||
ret := llvm.ConstNull(stringType)
|
||||
@@ -420,15 +402,9 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||
return nil, nil, fr.errorAt(inst, errors.New("interp: trying to copy a slice with negative length?"))
|
||||
}
|
||||
for i := int64(0); i < length; i++ {
|
||||
var err error
|
||||
// *dst = *src
|
||||
val, err := srcArray.Load()
|
||||
if err != nil {
|
||||
return nil, nil, fr.errorAt(inst, err)
|
||||
}
|
||||
err = dstArray.Store(val)
|
||||
if err != nil {
|
||||
return nil, nil, fr.errorAt(inst, err)
|
||||
}
|
||||
dstArray.Store(srcArray.Load())
|
||||
// dst++
|
||||
dstArrayValue, err := dstArray.GetElementPtr([]uint32{1})
|
||||
if err != nil {
|
||||
@@ -446,10 +422,7 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
|
||||
// convert a string to a []byte
|
||||
bufPtr := fr.getLocal(inst.Operand(0))
|
||||
bufLen := fr.getLocal(inst.Operand(1))
|
||||
result, err := getStringBytes(bufPtr, bufLen.Value())
|
||||
if err != nil {
|
||||
return nil, nil, fr.errorAt(inst, err)
|
||||
}
|
||||
result := getStringBytes(bufPtr, bufLen.Value())
|
||||
vals := make([]llvm.Value, len(result))
|
||||
for i := range vals {
|
||||
vals[i] = llvm.ConstInt(fr.Mod.Context().Int8Type(), uint64(result[i]), false)
|
||||
|
||||
+2
-15
@@ -3,7 +3,6 @@ package interp
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -67,8 +66,6 @@ func runTest(t *testing.T, pathPrefix string) {
|
||||
}
|
||||
}
|
||||
|
||||
var alignRegexp = regexp.MustCompile(", align [0-9]+$")
|
||||
|
||||
// fuzzyEqualIR returns true if the two LLVM IR strings passed in are roughly
|
||||
// equal. That means, only relevant lines are compared (excluding comments
|
||||
// etc.).
|
||||
@@ -78,18 +75,8 @@ func fuzzyEqualIR(s1, s2 string) bool {
|
||||
if len(lines1) != len(lines2) {
|
||||
return false
|
||||
}
|
||||
for i, line1 := range lines1 {
|
||||
line2 := lines2[i]
|
||||
match1 := alignRegexp.MatchString(line1)
|
||||
match2 := alignRegexp.MatchString(line2)
|
||||
if match1 != match2 {
|
||||
// Only one of the lines has the align keyword. Remove it.
|
||||
// This is a change to make the test work in both LLVM 10 and LLVM
|
||||
// 11 (LLVM 11 appears to automatically add alignment everywhere).
|
||||
line1 = alignRegexp.ReplaceAllString(line1, "")
|
||||
line2 = alignRegexp.ReplaceAllString(line2, "")
|
||||
}
|
||||
if line1 != line2 {
|
||||
for i, line := range lines1 {
|
||||
if line != lines2[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,10 +62,6 @@ func (e *evalPackage) hasSideEffects(fn llvm.Value) (*sideEffectResult, *Error)
|
||||
return &sideEffectResult{severity: sideEffectNone}, nil
|
||||
case name == "llvm.dbg.value":
|
||||
return &sideEffectResult{severity: sideEffectNone}, nil
|
||||
case name == "(*sync/atomic.Value).Load" || name == "(*sync/atomic.Value).Store":
|
||||
// These functions do some unsafe pointer loading/storing but are
|
||||
// otherwise safe.
|
||||
return &sideEffectResult{severity: sideEffectLimited}, nil
|
||||
case strings.HasPrefix(name, "llvm.lifetime."):
|
||||
return &sideEffectResult{severity: sideEffectNone}, nil
|
||||
}
|
||||
@@ -126,8 +122,6 @@ func (e *evalPackage) hasSideEffects(fn llvm.Value) (*sideEffectResult, *Error)
|
||||
// External function call. Assume only limited side effects
|
||||
// (no affected globals, etc.).
|
||||
switch child.Name() {
|
||||
case "runtime.alloc":
|
||||
continue
|
||||
case "runtime.typeAssert":
|
||||
continue // implemented in interp
|
||||
case "runtime.interfaceImplements":
|
||||
|
||||
+5
-10
@@ -1,8 +1,6 @@
|
||||
package interp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
@@ -20,23 +18,20 @@ func getUses(value llvm.Value) []llvm.Value {
|
||||
|
||||
// getStringBytes loads the byte slice of a Go string represented as a
|
||||
// {ptr, len} pair.
|
||||
func getStringBytes(strPtr Value, strLen llvm.Value) ([]byte, error) {
|
||||
func getStringBytes(strPtr Value, strLen llvm.Value) []byte {
|
||||
if !strLen.IsConstant() {
|
||||
return nil, errors.New("getStringBytes with a non-constant length")
|
||||
panic("getStringBytes with a non-constant length")
|
||||
}
|
||||
buf := make([]byte, strLen.ZExtValue())
|
||||
for i := range buf {
|
||||
gep, err := strPtr.GetElementPtr([]uint32{uint32(i)})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err := gep.Load()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
panic(err) // TODO
|
||||
}
|
||||
c := gep.Load()
|
||||
buf[i] = byte(c.ZExtValue())
|
||||
}
|
||||
return buf, nil
|
||||
return buf
|
||||
}
|
||||
|
||||
// getLLVMIndices converts an []uint32 into an []llvm.Value, for use in
|
||||
|
||||
+86
-80
@@ -15,8 +15,8 @@ type Value interface {
|
||||
Value() llvm.Value // returns a LLVM value
|
||||
Type() llvm.Type // equal to Value().Type()
|
||||
IsConstant() bool // returns true if this value is a constant value
|
||||
Load() (llvm.Value, error) // dereference a pointer
|
||||
Store(llvm.Value) error // store to a pointer
|
||||
Load() llvm.Value // dereference a pointer
|
||||
Store(llvm.Value) // store to a pointer
|
||||
GetElementPtr([]uint32) (Value, error) // returns an interior pointer
|
||||
String() string // string representation, for debugging
|
||||
}
|
||||
@@ -44,32 +44,29 @@ func (v *LocalValue) IsConstant() bool {
|
||||
}
|
||||
|
||||
// Load loads a constant value if this is a constant pointer.
|
||||
func (v *LocalValue) Load() (llvm.Value, error) {
|
||||
func (v *LocalValue) Load() llvm.Value {
|
||||
if !v.Underlying.IsAGlobalVariable().IsNil() {
|
||||
return v.Underlying.Initializer(), nil
|
||||
return v.Underlying.Initializer()
|
||||
}
|
||||
switch v.Underlying.Opcode() {
|
||||
case llvm.GetElementPtr:
|
||||
indices := v.getConstGEPIndices()
|
||||
if indices[0] != 0 {
|
||||
return llvm.Value{}, errors.New("invalid GEP")
|
||||
panic("invalid GEP")
|
||||
}
|
||||
global := v.Eval.getValue(v.Underlying.Operand(0))
|
||||
agg, err := global.Load()
|
||||
if err != nil {
|
||||
return llvm.Value{}, err
|
||||
}
|
||||
return llvm.ConstExtractValue(agg, indices[1:]), nil
|
||||
agg := global.Load()
|
||||
return llvm.ConstExtractValue(agg, indices[1:])
|
||||
case llvm.BitCast:
|
||||
return llvm.Value{}, errors.New("interp: load from a bitcast")
|
||||
panic("interp: load from a bitcast")
|
||||
default:
|
||||
return llvm.Value{}, errors.New("interp: load from a constant")
|
||||
panic("interp: load from a constant")
|
||||
}
|
||||
}
|
||||
|
||||
// Store stores to the underlying value if the value type is a pointer type,
|
||||
// otherwise it returns an error.
|
||||
func (v *LocalValue) Store(value llvm.Value) error {
|
||||
// otherwise it panics.
|
||||
func (v *LocalValue) Store(value llvm.Value) {
|
||||
if !v.Underlying.IsAGlobalVariable().IsNil() {
|
||||
if !value.IsConstant() {
|
||||
v.MarkDirty()
|
||||
@@ -77,28 +74,26 @@ func (v *LocalValue) Store(value llvm.Value) error {
|
||||
} else {
|
||||
v.Underlying.SetInitializer(value)
|
||||
}
|
||||
return nil
|
||||
return
|
||||
}
|
||||
if !value.IsConstant() {
|
||||
v.MarkDirty()
|
||||
v.Eval.builder.CreateStore(value, v.Underlying)
|
||||
return nil
|
||||
return
|
||||
}
|
||||
switch v.Underlying.Opcode() {
|
||||
case llvm.GetElementPtr:
|
||||
indices := v.getConstGEPIndices()
|
||||
if indices[0] != 0 {
|
||||
return errors.New("invalid GEP")
|
||||
panic("invalid GEP")
|
||||
}
|
||||
global := &LocalValue{v.Eval, v.Underlying.Operand(0)}
|
||||
agg, err := global.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
agg := global.Load()
|
||||
agg = llvm.ConstInsertValue(agg, value, indices[1:])
|
||||
return global.Store(agg)
|
||||
global.Store(agg)
|
||||
return
|
||||
default:
|
||||
return errors.New("interp: store on a constant")
|
||||
panic("interp: store on a constant")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,6 +178,8 @@ type MapValue struct {
|
||||
ValueSize int
|
||||
KeyType llvm.Type
|
||||
ValueType llvm.Type
|
||||
MapType llvm.Type // *%runtime.hashmap
|
||||
keyVariant string
|
||||
}
|
||||
|
||||
func (v *MapValue) newBucket() llvm.Value {
|
||||
@@ -226,31 +223,32 @@ func (v *MapValue) Value() llvm.Value {
|
||||
var keyBuf []byte
|
||||
llvmKey := key.Value()
|
||||
llvmValue := v.Values[i].Value()
|
||||
if key.Type().TypeKind() == llvm.StructTypeKind && key.Type().StructName() == "runtime._string" {
|
||||
switch v.keyVariant {
|
||||
case "string":
|
||||
keyPtr := llvm.ConstExtractValue(llvmKey, []uint32{0})
|
||||
keyLen := llvm.ConstExtractValue(llvmKey, []uint32{1})
|
||||
keyPtrVal := v.Eval.getValue(keyPtr)
|
||||
var err error
|
||||
keyBuf, err = getStringBytes(keyPtrVal, keyLen)
|
||||
if err != nil {
|
||||
panic(err) // TODO
|
||||
keyBuf = getStringBytes(keyPtrVal, keyLen)
|
||||
case "binary":
|
||||
if key.Type().TypeKind() == llvm.IntegerTypeKind {
|
||||
keyBuf = make([]byte, v.Eval.TargetData.TypeAllocSize(key.Type()))
|
||||
n := key.Value().ZExtValue()
|
||||
for i := range keyBuf {
|
||||
keyBuf[i] = byte(n)
|
||||
n >>= 8
|
||||
}
|
||||
} else if key.Type().TypeKind() == llvm.ArrayTypeKind &&
|
||||
key.Type().ElementType().TypeKind() == llvm.IntegerTypeKind &&
|
||||
key.Type().ElementType().IntTypeWidth() == 8 {
|
||||
keyBuf = make([]byte, v.Eval.TargetData.TypeAllocSize(key.Type()))
|
||||
for i := range keyBuf {
|
||||
keyBuf[i] = byte(llvm.ConstExtractValue(llvmKey, []uint32{uint32(i)}).ZExtValue())
|
||||
}
|
||||
} else {
|
||||
panic("interp: map key type not implemented: " + key.Type().String())
|
||||
}
|
||||
} else if key.Type().TypeKind() == llvm.IntegerTypeKind {
|
||||
keyBuf = make([]byte, v.Eval.TargetData.TypeAllocSize(key.Type()))
|
||||
n := key.Value().ZExtValue()
|
||||
for i := range keyBuf {
|
||||
keyBuf[i] = byte(n)
|
||||
n >>= 8
|
||||
}
|
||||
} else if key.Type().TypeKind() == llvm.ArrayTypeKind &&
|
||||
key.Type().ElementType().TypeKind() == llvm.IntegerTypeKind &&
|
||||
key.Type().ElementType().IntTypeWidth() == 8 {
|
||||
keyBuf = make([]byte, v.Eval.TargetData.TypeAllocSize(key.Type()))
|
||||
for i := range keyBuf {
|
||||
keyBuf[i] = byte(llvm.ConstExtractValue(llvmKey, []uint32{uint32(i)}).ZExtValue())
|
||||
}
|
||||
} else {
|
||||
panic("interp: map key type not implemented: " + key.Type().String())
|
||||
default:
|
||||
panic("interp: map key variant: " + v.keyVariant)
|
||||
}
|
||||
hash := v.hash(keyBuf)
|
||||
|
||||
@@ -300,7 +298,7 @@ func (v *MapValue) Value() llvm.Value {
|
||||
|
||||
// Type returns type runtime.hashmap, which is the actual hashmap type.
|
||||
func (v *MapValue) Type() llvm.Type {
|
||||
return v.Eval.Mod.GetTypeByName("runtime.hashmap")
|
||||
return v.MapType
|
||||
}
|
||||
|
||||
func (v *MapValue) IsConstant() bool {
|
||||
@@ -308,15 +306,13 @@ func (v *MapValue) IsConstant() bool {
|
||||
}
|
||||
|
||||
// Load panics: maps are of reference type so cannot be dereferenced.
|
||||
func (v *MapValue) Load() (llvm.Value, error) {
|
||||
func (v *MapValue) Load() llvm.Value {
|
||||
panic("interp: load from a map")
|
||||
}
|
||||
|
||||
// Store returns an error: maps are of reference type so cannot be stored to.
|
||||
func (v *MapValue) Store(value llvm.Value) error {
|
||||
// This must be a bug, but it might be helpful to indicate the location
|
||||
// anyway.
|
||||
return errors.New("interp: store on a map")
|
||||
// Store panics: maps are of reference type so cannot be stored to.
|
||||
func (v *MapValue) Store(value llvm.Value) {
|
||||
panic("interp: store on a map")
|
||||
}
|
||||
|
||||
// GetElementPtr panics: maps are of reference type so their (interior)
|
||||
@@ -325,65 +321,80 @@ func (v *MapValue) GetElementPtr(indices []uint32) (Value, error) {
|
||||
return nil, errors.New("interp: GEP on a map")
|
||||
}
|
||||
|
||||
// setKeyVariant sets the key variant as a result of storing to the hashmap
|
||||
// (string, binary, or interface). The way that TinyGo is structured, the key
|
||||
// variant is not known until there is a store to the hashmap.
|
||||
// The key variant has to be known when lowering the hashmap to its final form,
|
||||
// to correctly calculate the hash of a key (for example, a string key must
|
||||
// calculate the hash over the string contents).
|
||||
func (v *MapValue) setKeyVariant(keyVariant string) {
|
||||
if v.keyVariant == "" {
|
||||
v.keyVariant = keyVariant
|
||||
return
|
||||
}
|
||||
if v.keyVariant != keyVariant {
|
||||
// Valid IR will not cause this panic to occur.
|
||||
panic("MapValue store with inconsistent key type")
|
||||
}
|
||||
}
|
||||
|
||||
// PutString does a map assign operation, assuming that the map is of type
|
||||
// map[string]T.
|
||||
func (v *MapValue) PutString(keyBuf, keyLen, valPtr *LocalValue) error {
|
||||
func (v *MapValue) PutString(keyBuf, keyLen, valPtr *LocalValue) {
|
||||
if !v.Underlying.IsNil() {
|
||||
return errors.New("map already created")
|
||||
panic("map already created")
|
||||
}
|
||||
v.setKeyVariant("string")
|
||||
|
||||
if valPtr.Underlying.Opcode() == llvm.BitCast {
|
||||
valPtr = &LocalValue{v.Eval, valPtr.Underlying.Operand(0)}
|
||||
}
|
||||
value, err := valPtr.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value := valPtr.Load()
|
||||
if v.ValueType.IsNil() {
|
||||
v.ValueType = value.Type()
|
||||
if int(v.Eval.TargetData.TypeAllocSize(v.ValueType)) != v.ValueSize {
|
||||
return errors.New("interp: map store value type has the wrong size")
|
||||
panic("interp: map store value type has the wrong size")
|
||||
}
|
||||
} else {
|
||||
if value.Type() != v.ValueType {
|
||||
return errors.New("interp: map store value type is inconsistent")
|
||||
panic("interp: map store value type is inconsistent")
|
||||
}
|
||||
}
|
||||
|
||||
keyType := v.Eval.Mod.GetTypeByName("runtime._string")
|
||||
v.KeyType = keyType
|
||||
key := llvm.ConstNull(keyType)
|
||||
if v.KeyType.IsNil() {
|
||||
v.KeyType = v.Eval.Mod.Context().StructType([]llvm.Type{
|
||||
keyBuf.Type(),
|
||||
keyLen.Type(),
|
||||
}, false)
|
||||
}
|
||||
key := llvm.ConstNull(v.KeyType)
|
||||
key = llvm.ConstInsertValue(key, keyBuf.Value(), []uint32{0})
|
||||
key = llvm.ConstInsertValue(key, keyLen.Value(), []uint32{1})
|
||||
|
||||
// TODO: avoid duplicate keys
|
||||
v.Keys = append(v.Keys, &LocalValue{v.Eval, key})
|
||||
v.Values = append(v.Values, &LocalValue{v.Eval, value})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PutBinary does a map assign operation.
|
||||
func (v *MapValue) PutBinary(keyPtr, valPtr *LocalValue) error {
|
||||
func (v *MapValue) PutBinary(keyPtr, valPtr *LocalValue) {
|
||||
if !v.Underlying.IsNil() {
|
||||
return errors.New("map already created")
|
||||
panic("map already created")
|
||||
}
|
||||
v.setKeyVariant("binary")
|
||||
|
||||
if valPtr.Underlying.Opcode() == llvm.BitCast {
|
||||
valPtr = &LocalValue{v.Eval, valPtr.Underlying.Operand(0)}
|
||||
}
|
||||
value, err := valPtr.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
value := valPtr.Load()
|
||||
if v.ValueType.IsNil() {
|
||||
v.ValueType = value.Type()
|
||||
if int(v.Eval.TargetData.TypeAllocSize(v.ValueType)) != v.ValueSize {
|
||||
return errors.New("interp: map store value type has the wrong size")
|
||||
panic("interp: map store value type has the wrong size")
|
||||
}
|
||||
} else {
|
||||
if value.Type() != v.ValueType {
|
||||
return errors.New("interp: map store value type is inconsistent")
|
||||
panic("interp: map store value type is inconsistent")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,26 +405,21 @@ func (v *MapValue) PutBinary(keyPtr, valPtr *LocalValue) error {
|
||||
keyPtr = &LocalValue{v.Eval, keyPtr.Underlying.Operand(0)}
|
||||
}
|
||||
}
|
||||
key, err := keyPtr.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := keyPtr.Load()
|
||||
if v.KeyType.IsNil() {
|
||||
v.KeyType = key.Type()
|
||||
if int(v.Eval.TargetData.TypeAllocSize(v.KeyType)) != v.KeySize {
|
||||
return errors.New("interp: map store key type has the wrong size")
|
||||
panic("interp: map store key type has the wrong size")
|
||||
}
|
||||
} else {
|
||||
if key.Type() != v.KeyType {
|
||||
return errors.New("interp: map store key type is inconsistent")
|
||||
panic("interp: map store key type is inconsistent")
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: avoid duplicate keys
|
||||
v.Keys = append(v.Keys, &LocalValue{v.Eval, key})
|
||||
v.Values = append(v.Values, &LocalValue{v.Eval, value})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get FNV-1a hash of this string.
|
||||
|
||||
@@ -1,271 +0,0 @@
|
||||
package ir
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"go/types"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/tinygo-org/tinygo/loader"
|
||||
"golang.org/x/tools/go/ssa"
|
||||
"tinygo.org/x/go-llvm"
|
||||
)
|
||||
|
||||
// This file provides a wrapper around go/ssa values and adds extra
|
||||
// functionality to them.
|
||||
|
||||
// View on all functions, types, and globals in a program, with analysis
|
||||
// results.
|
||||
type Program struct {
|
||||
Program *ssa.Program
|
||||
LoaderProgram *loader.Program
|
||||
mainPkg *ssa.Package
|
||||
Functions []*Function
|
||||
functionMap map[*ssa.Function]*Function
|
||||
}
|
||||
|
||||
// Function or method.
|
||||
type Function struct {
|
||||
*ssa.Function
|
||||
LLVMFn llvm.Value
|
||||
module string // go:wasm-module
|
||||
linkName string // go:linkname, go:export
|
||||
exported bool // go:export
|
||||
nobounds bool // go:nobounds
|
||||
flag bool // used by dead code elimination
|
||||
inline InlineType // go:inline
|
||||
}
|
||||
|
||||
// Interface type that is at some point used in a type assert (to check whether
|
||||
// it implements another interface).
|
||||
type Interface struct {
|
||||
Num int
|
||||
Type *types.Interface
|
||||
}
|
||||
|
||||
type InlineType int
|
||||
|
||||
// How much to inline.
|
||||
const (
|
||||
// Default behavior. The compiler decides for itself whether any given
|
||||
// function will be inlined. Whether any function is inlined depends on the
|
||||
// optimization level.
|
||||
InlineDefault InlineType = iota
|
||||
|
||||
// Inline hint, just like the C inline keyword (signalled using
|
||||
// //go:inline). The compiler will be more likely to inline this function,
|
||||
// but it is not a guarantee.
|
||||
InlineHint
|
||||
|
||||
// Don't inline, just like the GCC noinline attribute. Signalled using
|
||||
// //go:noinline.
|
||||
InlineNone
|
||||
)
|
||||
|
||||
// Create and initialize a new *Program from a *ssa.Program.
|
||||
func NewProgram(lprogram *loader.Program) *Program {
|
||||
program := lprogram.LoadSSA()
|
||||
program.Build()
|
||||
|
||||
mainPkg := program.ImportedPackage(lprogram.MainPkg().ImportPath)
|
||||
if mainPkg == nil {
|
||||
panic("could not find main package")
|
||||
}
|
||||
p := &Program{
|
||||
Program: program,
|
||||
LoaderProgram: lprogram,
|
||||
mainPkg: mainPkg,
|
||||
functionMap: make(map[*ssa.Function]*Function),
|
||||
}
|
||||
|
||||
for _, pkg := range lprogram.Sorted() {
|
||||
p.AddPackage(program.ImportedPackage(pkg.ImportPath))
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// Add a package to this Program. All packages need to be added first before any
|
||||
// analysis is done for correct results.
|
||||
func (p *Program) AddPackage(pkg *ssa.Package) {
|
||||
memberNames := make([]string, 0)
|
||||
for name := range pkg.Members {
|
||||
memberNames = append(memberNames, name)
|
||||
}
|
||||
sort.Strings(memberNames)
|
||||
|
||||
for _, name := range memberNames {
|
||||
member := pkg.Members[name]
|
||||
switch member := member.(type) {
|
||||
case *ssa.Function:
|
||||
p.addFunction(member)
|
||||
case *ssa.Type:
|
||||
methods := getAllMethods(pkg.Prog, member.Type())
|
||||
if !types.IsInterface(member.Type()) {
|
||||
// named type
|
||||
for _, method := range methods {
|
||||
p.addFunction(pkg.Prog.MethodValue(method))
|
||||
}
|
||||
}
|
||||
case *ssa.Global:
|
||||
// Ignore. Globals are not handled here.
|
||||
case *ssa.NamedConst:
|
||||
// Ignore: these are already resolved.
|
||||
default:
|
||||
panic("unknown member type: " + member.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Program) addFunction(ssaFn *ssa.Function) {
|
||||
if _, ok := p.functionMap[ssaFn]; ok {
|
||||
return
|
||||
}
|
||||
f := &Function{Function: ssaFn}
|
||||
f.parsePragmas()
|
||||
p.Functions = append(p.Functions, f)
|
||||
p.functionMap[ssaFn] = f
|
||||
|
||||
for _, anon := range ssaFn.AnonFuncs {
|
||||
p.addFunction(anon)
|
||||
}
|
||||
}
|
||||
|
||||
// Return true if this package imports "unsafe", false otherwise.
|
||||
func hasUnsafeImport(pkg *types.Package) bool {
|
||||
for _, imp := range pkg.Imports() {
|
||||
if imp == types.Unsafe {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Program) GetFunction(ssaFn *ssa.Function) *Function {
|
||||
return p.functionMap[ssaFn]
|
||||
}
|
||||
|
||||
func (p *Program) MainPkg() *ssa.Package {
|
||||
return p.mainPkg
|
||||
}
|
||||
|
||||
// Parse compiler directives in the preceding comments.
|
||||
func (f *Function) parsePragmas() {
|
||||
if f.Syntax() == nil {
|
||||
return
|
||||
}
|
||||
if decl, ok := f.Syntax().(*ast.FuncDecl); ok && decl.Doc != nil {
|
||||
for _, comment := range decl.Doc.List {
|
||||
text := comment.Text
|
||||
if strings.HasPrefix(text, "//export ") {
|
||||
// Rewrite '//export' to '//go:export' for compatibility with
|
||||
// gc.
|
||||
text = "//go:" + text[2:]
|
||||
}
|
||||
if !strings.HasPrefix(text, "//go:") {
|
||||
continue
|
||||
}
|
||||
parts := strings.Fields(text)
|
||||
switch parts[0] {
|
||||
case "//go:export":
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
f.linkName = parts[1]
|
||||
f.exported = true
|
||||
case "//go:wasm-module":
|
||||
// Alternative comment for setting the import module.
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
f.module = parts[1]
|
||||
case "//go:inline":
|
||||
f.inline = InlineHint
|
||||
case "//go:noinline":
|
||||
f.inline = InlineNone
|
||||
case "//go:linkname":
|
||||
if len(parts) != 3 || parts[1] != f.Name() {
|
||||
continue
|
||||
}
|
||||
// Only enable go:linkname when the package imports "unsafe".
|
||||
// This is a slightly looser requirement than what gc uses: gc
|
||||
// requires the file to import "unsafe", not the package as a
|
||||
// whole.
|
||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||
f.linkName = parts[2]
|
||||
}
|
||||
case "//go:nobounds":
|
||||
// Skip bounds checking in this function. Useful for some
|
||||
// runtime functions.
|
||||
// This is somewhat dangerous and thus only imported in packages
|
||||
// that import unsafe.
|
||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||
f.nobounds = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (f *Function) IsNoBounds() bool {
|
||||
return f.nobounds
|
||||
}
|
||||
|
||||
// Return true iff this function is externally visible.
|
||||
func (f *Function) IsExported() bool {
|
||||
return f.exported || f.CName() != ""
|
||||
}
|
||||
|
||||
// Return the inline directive of this function.
|
||||
func (f *Function) Inline() InlineType {
|
||||
return f.inline
|
||||
}
|
||||
|
||||
// Return the module name if not the default.
|
||||
func (f *Function) Module() string {
|
||||
return f.module
|
||||
}
|
||||
|
||||
// Return the link name for this function.
|
||||
func (f *Function) LinkName() string {
|
||||
if f.linkName != "" {
|
||||
return f.linkName
|
||||
}
|
||||
if f.Signature.Recv() != nil {
|
||||
// Method on a defined type (which may be a pointer).
|
||||
return f.RelString(nil)
|
||||
} else {
|
||||
// Bare function.
|
||||
if name := f.CName(); name != "" {
|
||||
// Name CGo functions directly.
|
||||
return name
|
||||
} else {
|
||||
return f.RelString(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the name of the C function if this is a CGo wrapper. Otherwise, return
|
||||
// a zero-length string.
|
||||
func (f *Function) CName() string {
|
||||
name := f.Name()
|
||||
if strings.HasPrefix(name, "_Cfunc_") {
|
||||
// emitted by `go tool cgo`
|
||||
return name[len("_Cfunc_"):]
|
||||
}
|
||||
if strings.HasPrefix(name, "C.") {
|
||||
// created by ../loader/cgo.go
|
||||
return name[2:]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Get all methods of a type.
|
||||
func getAllMethods(prog *ssa.Program, typ types.Type) []*types.Selection {
|
||||
ms := prog.MethodSets.MethodSet(typ)
|
||||
methods := make([]*types.Selection, ms.Len())
|
||||
for i := 0; i < ms.Len(); i++ {
|
||||
methods[i] = ms.At(i)
|
||||
}
|
||||
return methods
|
||||
}
|
||||
-149
@@ -1,149 +0,0 @@
|
||||
package ir
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"go/types"
|
||||
|
||||
"golang.org/x/tools/go/ssa"
|
||||
)
|
||||
|
||||
// This file implements several optimization passes (analysis + transform) to
|
||||
// optimize code in SSA form before it is compiled to LLVM IR. It is based on
|
||||
// the IR defined in ir.go.
|
||||
|
||||
// Make a readable version of a method signature (including the function name,
|
||||
// excluding the receiver name). This string is used internally to match
|
||||
// interfaces and to call the correct method on an interface. Examples:
|
||||
//
|
||||
// String() string
|
||||
// Read([]byte) (int, error)
|
||||
func MethodSignature(method *types.Func) string {
|
||||
return method.Name() + signature(method.Type().(*types.Signature))
|
||||
}
|
||||
|
||||
// Make a readable version of a function (pointer) signature.
|
||||
// Examples:
|
||||
//
|
||||
// () string
|
||||
// (string, int) (int, error)
|
||||
func signature(sig *types.Signature) string {
|
||||
s := ""
|
||||
if sig.Params().Len() == 0 {
|
||||
s += "()"
|
||||
} else {
|
||||
s += "("
|
||||
for i := 0; i < sig.Params().Len(); i++ {
|
||||
if i > 0 {
|
||||
s += ", "
|
||||
}
|
||||
s += sig.Params().At(i).Type().String()
|
||||
}
|
||||
s += ")"
|
||||
}
|
||||
if sig.Results().Len() == 0 {
|
||||
// keep as-is
|
||||
} else if sig.Results().Len() == 1 {
|
||||
s += " " + sig.Results().At(0).Type().String()
|
||||
} else {
|
||||
s += " ("
|
||||
for i := 0; i < sig.Results().Len(); i++ {
|
||||
if i > 0 {
|
||||
s += ", "
|
||||
}
|
||||
s += sig.Results().At(i).Type().String()
|
||||
}
|
||||
s += ")"
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Simple pass that removes dead code. This pass makes later analysis passes
|
||||
// more useful.
|
||||
func (p *Program) SimpleDCE() error {
|
||||
// Unmark all functions.
|
||||
for _, f := range p.Functions {
|
||||
f.flag = false
|
||||
}
|
||||
|
||||
// Initial set of live functions. Include main.main, *.init and runtime.*
|
||||
// functions.
|
||||
main, ok := p.mainPkg.Members["main"].(*ssa.Function)
|
||||
if !ok {
|
||||
if p.mainPkg.Members["main"] == nil {
|
||||
return errors.New("function main is undeclared in the main package")
|
||||
} else {
|
||||
return errors.New("cannot declare main - must be func")
|
||||
}
|
||||
}
|
||||
runtimePkg := p.Program.ImportedPackage("runtime")
|
||||
mathPkg := p.Program.ImportedPackage("math")
|
||||
taskPkg := p.Program.ImportedPackage("internal/task")
|
||||
p.GetFunction(main).flag = true
|
||||
worklist := []*ssa.Function{main}
|
||||
for _, f := range p.Functions {
|
||||
if f.exported || f.Synthetic == "package initializer" || f.Pkg == runtimePkg || f.Pkg == taskPkg || (f.Pkg == mathPkg && f.Pkg != nil) {
|
||||
if f.flag {
|
||||
continue
|
||||
}
|
||||
f.flag = true
|
||||
worklist = append(worklist, f.Function)
|
||||
}
|
||||
}
|
||||
|
||||
// Mark all called functions recursively.
|
||||
for len(worklist) != 0 {
|
||||
f := worklist[len(worklist)-1]
|
||||
worklist = worklist[:len(worklist)-1]
|
||||
for _, block := range f.Blocks {
|
||||
for _, instr := range block.Instrs {
|
||||
if instr, ok := instr.(*ssa.MakeInterface); ok {
|
||||
for _, sel := range getAllMethods(p.Program, instr.X.Type()) {
|
||||
fn := p.Program.MethodValue(sel)
|
||||
callee := p.GetFunction(fn)
|
||||
if callee == nil {
|
||||
// TODO: why is this necessary?
|
||||
p.addFunction(fn)
|
||||
callee = p.GetFunction(fn)
|
||||
}
|
||||
if !callee.flag {
|
||||
callee.flag = true
|
||||
worklist = append(worklist, callee.Function)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, operand := range instr.Operands(nil) {
|
||||
if operand == nil || *operand == nil {
|
||||
continue
|
||||
}
|
||||
switch operand := (*operand).(type) {
|
||||
case *ssa.Function:
|
||||
f := p.GetFunction(operand)
|
||||
if f == nil {
|
||||
// FIXME HACK: this function should have been
|
||||
// discovered already. It is not for bound methods.
|
||||
p.addFunction(operand)
|
||||
f = p.GetFunction(operand)
|
||||
}
|
||||
if !f.flag {
|
||||
f.flag = true
|
||||
worklist = append(worklist, operand)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove unmarked functions.
|
||||
livefunctions := []*Function{}
|
||||
for _, f := range p.Functions {
|
||||
if f.flag {
|
||||
livefunctions = append(livefunctions, f)
|
||||
} else {
|
||||
delete(p.functionMap, f.Function)
|
||||
}
|
||||
}
|
||||
p.Functions = livefunctions
|
||||
|
||||
return nil
|
||||
}
|
||||
+1
-1
Submodule lib/cmsis-svd updated: d9b58694ce...15b462f152
+1
-1
Submodule lib/wasi-libc updated: 215adc8ac9...a280fead2a
+22
-8
@@ -1,6 +1,9 @@
|
||||
package loader
|
||||
|
||||
import "go/scanner"
|
||||
import (
|
||||
"go/token"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Errors contains a list of parser errors or a list of typechecker errors for
|
||||
// the given package.
|
||||
@@ -13,13 +16,24 @@ func (e Errors) Error() string {
|
||||
return "could not compile: " + e.Errs[0].Error()
|
||||
}
|
||||
|
||||
// Error is a regular error but with an added import stack. This is especially
|
||||
// useful for debugging import cycle errors.
|
||||
type Error struct {
|
||||
ImportStack []string
|
||||
Err scanner.Error
|
||||
// ImportCycleErrors is returned when encountering an import cycle. The list of
|
||||
// packages is a list from the root package to the leaf package that imports one
|
||||
// of the packages in the list.
|
||||
type ImportCycleError struct {
|
||||
Packages []string
|
||||
ImportPositions []token.Position
|
||||
}
|
||||
|
||||
func (e Error) Error() string {
|
||||
return e.Err.Error()
|
||||
func (e *ImportCycleError) Error() string {
|
||||
var msg strings.Builder
|
||||
msg.WriteString("import cycle:\n\t")
|
||||
msg.WriteString(strings.Join(e.Packages, "\n\t"))
|
||||
msg.WriteString("\n at ")
|
||||
for i, pos := range e.ImportPositions {
|
||||
if i > 0 {
|
||||
msg.WriteString(", ")
|
||||
}
|
||||
msg.WriteString(pos.String())
|
||||
}
|
||||
return msg.String()
|
||||
}
|
||||
|
||||
@@ -1,281 +0,0 @@
|
||||
package loader
|
||||
|
||||
// This file constructs a new temporary GOROOT directory by merging both the
|
||||
// standard Go GOROOT and the GOROOT from TinyGo using symlinks.
|
||||
|
||||
import (
|
||||
"crypto/sha512"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
)
|
||||
|
||||
var gorootCreateMutex sync.Mutex
|
||||
|
||||
// GetCachedGoroot creates a new GOROOT by merging both the standard GOROOT and
|
||||
// the GOROOT from TinyGo using lots of symbolic links.
|
||||
func GetCachedGoroot(config *compileopts.Config) (string, error) {
|
||||
goroot := goenv.Get("GOROOT")
|
||||
if goroot == "" {
|
||||
return "", errors.New("could not determine GOROOT")
|
||||
}
|
||||
tinygoroot := goenv.Get("TINYGOROOT")
|
||||
if tinygoroot == "" {
|
||||
return "", errors.New("could not determine TINYGOROOT")
|
||||
}
|
||||
|
||||
// Determine the location of the cached GOROOT.
|
||||
version, err := goenv.GorootVersionString(goroot)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// This hash is really a cache key, that contains (hopefully) enough
|
||||
// information to make collisions unlikely during development.
|
||||
// By including the Go version and TinyGo version, cache collisions should
|
||||
// not happen outside of development.
|
||||
hash := sha512.New512_256()
|
||||
fmt.Fprintln(hash, goroot)
|
||||
fmt.Fprintln(hash, version)
|
||||
fmt.Fprintln(hash, goenv.Version)
|
||||
fmt.Fprintln(hash, tinygoroot)
|
||||
gorootsHash := hash.Sum(nil)
|
||||
gorootsHashHex := hex.EncodeToString(gorootsHash[:])
|
||||
cachedgorootName := "goroot-" + version + "-" + gorootsHashHex
|
||||
cachedgoroot := filepath.Join(goenv.Get("GOCACHE"), cachedgorootName)
|
||||
if needsSyscallPackage(config.BuildTags()) {
|
||||
cachedgoroot += "-syscall"
|
||||
}
|
||||
|
||||
// Do not try to create the cached GOROOT in parallel, that's only a waste
|
||||
// of I/O bandwidth and thus speed. Instead, use a mutex to make sure only
|
||||
// one goroutine does it at a time.
|
||||
// This is not a way to ensure atomicity (a different TinyGo invocation
|
||||
// could be creating the same directory), but instead a way to avoid
|
||||
// creating it many times in parallel when running tests in parallel.
|
||||
gorootCreateMutex.Lock()
|
||||
defer gorootCreateMutex.Unlock()
|
||||
|
||||
if _, err := os.Stat(cachedgoroot); err == nil {
|
||||
return cachedgoroot, nil
|
||||
}
|
||||
err = os.MkdirAll(goenv.Get("GOCACHE"), 0777)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tmpgoroot, err := ioutil.TempDir(goenv.Get("GOCACHE"), cachedgorootName+".tmp")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Remove the temporary directory if it wasn't moved to the right place
|
||||
// (for example, when there was an error).
|
||||
defer os.RemoveAll(tmpgoroot)
|
||||
|
||||
for _, name := range []string{"bin", "lib", "pkg"} {
|
||||
err = symlink(filepath.Join(goroot, name), filepath.Join(tmpgoroot, name))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
err = mergeDirectory(goroot, tinygoroot, tmpgoroot, "", pathsToOverride(needsSyscallPackage(config.BuildTags())))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
err = os.Rename(tmpgoroot, cachedgoroot)
|
||||
if err != nil {
|
||||
if os.IsExist(err) {
|
||||
// Another invocation of TinyGo also seems to have created a GOROOT.
|
||||
// Use that one instead. Our new GOROOT will be automatically
|
||||
// deleted by the defer above.
|
||||
return cachedgoroot, nil
|
||||
}
|
||||
if runtime.GOOS == "windows" && os.IsPermission(err) {
|
||||
// On Windows, a rename with a destination directory that already
|
||||
// exists does not result in an IsExist error, but rather in an
|
||||
// access denied error. To be sure, check for this case by checking
|
||||
// whether the target directory exists.
|
||||
if _, err := os.Stat(cachedgoroot); err == nil {
|
||||
return cachedgoroot, nil
|
||||
}
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return cachedgoroot, nil
|
||||
}
|
||||
|
||||
// mergeDirectory merges two roots recursively. The tmpgoroot is the directory
|
||||
// that will be created by this call by either symlinking the directory from
|
||||
// goroot or tinygoroot, or by creating the directory and merging the contents.
|
||||
func mergeDirectory(goroot, tinygoroot, tmpgoroot, importPath string, overrides map[string]bool) error {
|
||||
if mergeSubdirs, ok := overrides[importPath+"/"]; ok {
|
||||
if !mergeSubdirs {
|
||||
// This directory and all subdirectories should come from the TinyGo
|
||||
// root, so simply make a symlink.
|
||||
newname := filepath.Join(tmpgoroot, "src", importPath)
|
||||
oldname := filepath.Join(tinygoroot, "src", importPath)
|
||||
return symlink(oldname, newname)
|
||||
}
|
||||
|
||||
// Merge subdirectories. Start by making the directory to merge.
|
||||
err := os.Mkdir(filepath.Join(tmpgoroot, "src", importPath), 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Symlink all files from TinyGo, and symlink directories from TinyGo
|
||||
// that need to be overridden.
|
||||
tinygoEntries, err := ioutil.ReadDir(filepath.Join(tinygoroot, "src", importPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, e := range tinygoEntries {
|
||||
if e.IsDir() {
|
||||
// A directory, so merge this thing.
|
||||
err := mergeDirectory(goroot, tinygoroot, tmpgoroot, path.Join(importPath, e.Name()), overrides)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// A file, so symlink this.
|
||||
newname := filepath.Join(tmpgoroot, "src", importPath, e.Name())
|
||||
oldname := filepath.Join(tinygoroot, "src", importPath, e.Name())
|
||||
err := symlink(oldname, newname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Symlink all directories from $GOROOT that are not part of the TinyGo
|
||||
// overrides.
|
||||
gorootEntries, err := ioutil.ReadDir(filepath.Join(goroot, "src", importPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, e := range gorootEntries {
|
||||
if !e.IsDir() {
|
||||
// Don't merge in files from Go. Otherwise we'd end up with a
|
||||
// weird syscall package with files from both roots.
|
||||
continue
|
||||
}
|
||||
if _, ok := overrides[path.Join(importPath, e.Name())+"/"]; ok {
|
||||
// Already included above, so don't bother trying to create this
|
||||
// symlink.
|
||||
continue
|
||||
}
|
||||
newname := filepath.Join(tmpgoroot, "src", importPath, e.Name())
|
||||
oldname := filepath.Join(goroot, "src", importPath, e.Name())
|
||||
err := symlink(oldname, newname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// needsSyscallPackage returns whether the syscall package should be overriden
|
||||
// with the TinyGo version. This is the case on some targets.
|
||||
func needsSyscallPackage(buildTags []string) bool {
|
||||
for _, tag := range buildTags {
|
||||
if tag == "baremetal" || tag == "darwin" || tag == "nintendoswitch" || tag == "wasi" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// The boolean indicates whether to merge the subdirs. True means merge, false
|
||||
// means use the TinyGo version.
|
||||
func pathsToOverride(needsSyscallPackage bool) map[string]bool {
|
||||
paths := map[string]bool{
|
||||
"/": true,
|
||||
"device/": false,
|
||||
"examples/": false,
|
||||
"internal/": true,
|
||||
"internal/bytealg/": false,
|
||||
"internal/reflectlite/": false,
|
||||
"internal/task/": false,
|
||||
"machine/": false,
|
||||
"os/": true,
|
||||
"reflect/": false,
|
||||
"runtime/": false,
|
||||
"sync/": true,
|
||||
"testing/": true,
|
||||
}
|
||||
if needsSyscallPackage {
|
||||
paths["syscall/"] = true // include syscall/js
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
// symlink creates a symlink or something similar. On Unix-like systems, it
|
||||
// always creates a symlink. On Windows, it tries to create a symlink and if
|
||||
// that fails, creates a hardlink or directory junction instead.
|
||||
//
|
||||
// Note that while Windows 10 does support symlinks and allows them to be
|
||||
// created using os.Symlink, it requires developer mode to be enabled.
|
||||
// Therefore provide a fallback for when symlinking is not possible.
|
||||
// Unfortunately this fallback only works when TinyGo is installed on the same
|
||||
// filesystem as the TinyGo cache and the Go installation (which is usually the
|
||||
// C drive).
|
||||
func symlink(oldname, newname string) error {
|
||||
symlinkErr := os.Symlink(oldname, newname)
|
||||
if runtime.GOOS == "windows" && symlinkErr != nil {
|
||||
// Fallback for when developer mode is disabled.
|
||||
// Note that we return the symlink error even if something else fails
|
||||
// later on. This is because symlinks are the easiest to support
|
||||
// (they're also used on Linux and MacOS) and enabling them is easy:
|
||||
// just enable developer mode.
|
||||
st, err := os.Stat(oldname)
|
||||
if err != nil {
|
||||
return symlinkErr
|
||||
}
|
||||
if st.IsDir() {
|
||||
// Make a directory junction. There may be a way to do this
|
||||
// programmatically, but it involves a lot of magic. Use the mklink
|
||||
// command built into cmd instead (mklink is a builtin, not an
|
||||
// external command).
|
||||
err := exec.Command("cmd", "/k", "mklink", "/J", newname, oldname).Run()
|
||||
if err != nil {
|
||||
return symlinkErr
|
||||
}
|
||||
} else {
|
||||
// Try making a hard link.
|
||||
err := os.Link(oldname, newname)
|
||||
if err != nil {
|
||||
// Making a hardlink failed. Try copying the file as a last
|
||||
// fallback.
|
||||
inf, err := os.Open(oldname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer inf.Close()
|
||||
outf, err := os.Create(newname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer outf.Close()
|
||||
_, err = io.Copy(outf, inf)
|
||||
if err != nil {
|
||||
os.Remove(newname)
|
||||
return err
|
||||
}
|
||||
// File was copied.
|
||||
}
|
||||
}
|
||||
return nil // success
|
||||
}
|
||||
return symlinkErr
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package loader
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
)
|
||||
|
||||
// List returns a ready-to-run *exec.Cmd for running the `go list` command with
|
||||
// the configuration used for TinyGo.
|
||||
func List(config *compileopts.Config, extraArgs, pkgs []string) (*exec.Cmd, error) {
|
||||
goroot, err := GetCachedGoroot(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args := append([]string{"list"}, extraArgs...)
|
||||
if len(config.BuildTags()) != 0 {
|
||||
args = append(args, "-tags", strings.Join(config.BuildTags(), " "))
|
||||
}
|
||||
args = append(args, pkgs...)
|
||||
cgoEnabled := "0"
|
||||
if config.CgoEnabled() {
|
||||
cgoEnabled = "1"
|
||||
}
|
||||
cmd := exec.Command("go", args...)
|
||||
cmd.Env = append(os.Environ(), "GOROOT="+goroot, "GOOS="+config.GOOS(), "GOARCH="+config.GOARCH(), "CGO_ENABLED="+cgoEnabled)
|
||||
return cmd, nil
|
||||
}
|
||||
+345
-252
@@ -2,273 +2,226 @@ package loader
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/scanner"
|
||||
"go/token"
|
||||
"go/types"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
"text/template"
|
||||
|
||||
"github.com/tinygo-org/tinygo/cgo"
|
||||
"github.com/tinygo-org/tinygo/compileopts"
|
||||
"github.com/tinygo-org/tinygo/goenv"
|
||||
)
|
||||
|
||||
// Program holds all packages and some metadata about the program as a whole.
|
||||
type Program struct {
|
||||
config *compileopts.Config
|
||||
clangHeaders string
|
||||
typeChecker types.Config
|
||||
goroot string // synthetic GOROOT
|
||||
workingDir string
|
||||
|
||||
Packages map[string]*Package
|
||||
sorted []*Package
|
||||
fset *token.FileSet
|
||||
|
||||
// Information obtained during parsing.
|
||||
LDFlags []string
|
||||
}
|
||||
|
||||
// PackageJSON is a subset of the JSON struct returned from `go list`.
|
||||
type PackageJSON struct {
|
||||
Dir string
|
||||
ImportPath string
|
||||
ForTest string
|
||||
|
||||
// Source files
|
||||
GoFiles []string
|
||||
CgoFiles []string
|
||||
CFiles []string
|
||||
|
||||
// Dependency information
|
||||
Imports []string
|
||||
|
||||
// Error information
|
||||
Error *struct {
|
||||
ImportStack []string
|
||||
Pos string
|
||||
Err string
|
||||
}
|
||||
mainPkg string
|
||||
Build *build.Context
|
||||
OverlayBuild *build.Context
|
||||
OverlayPath func(path string) string
|
||||
Packages map[string]*Package
|
||||
sorted []*Package
|
||||
fset *token.FileSet
|
||||
TypeChecker types.Config
|
||||
Dir string // current working directory (for error reporting)
|
||||
TINYGOROOT string // root of the TinyGo installation or root of the source code
|
||||
CFlags []string
|
||||
ClangHeaders string
|
||||
}
|
||||
|
||||
// Package holds a loaded package, its imports, and its parsed files.
|
||||
type Package struct {
|
||||
PackageJSON
|
||||
|
||||
program *Program
|
||||
Files []*ast.File
|
||||
Pkg *types.Package
|
||||
info types.Info
|
||||
*Program
|
||||
*build.Package
|
||||
Imports map[string]*Package
|
||||
Importing bool
|
||||
Files []*ast.File
|
||||
Pkg *types.Package
|
||||
types.Info
|
||||
}
|
||||
|
||||
// Load loads the given package with all dependencies (including the runtime
|
||||
// package). Call .Parse() afterwards to parse all Go files (including CGo
|
||||
// processing, if necessary).
|
||||
func Load(config *compileopts.Config, inputPkgs []string, clangHeaders string, typeChecker types.Config) (*Program, error) {
|
||||
goroot, err := GetCachedGoroot(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p := &Program{
|
||||
config: config,
|
||||
clangHeaders: clangHeaders,
|
||||
typeChecker: typeChecker,
|
||||
goroot: goroot,
|
||||
workingDir: wd,
|
||||
Packages: make(map[string]*Package),
|
||||
fset: token.NewFileSet(),
|
||||
// Import loads the given package relative to srcDir (for the vendor directory).
|
||||
// It only loads the current package without recursion.
|
||||
func (p *Program) Import(path, srcDir string, pos token.Position) (*Package, error) {
|
||||
if p.Packages == nil {
|
||||
p.Packages = make(map[string]*Package)
|
||||
}
|
||||
|
||||
// List the dependencies of this package, in raw JSON format.
|
||||
extraArgs := []string{"-json", "-deps"}
|
||||
if config.TestConfig.CompileTestBinary {
|
||||
extraArgs = append(extraArgs, "-test")
|
||||
// Load this package.
|
||||
ctx := p.Build
|
||||
if newPath := p.OverlayPath(path); newPath != "" {
|
||||
ctx = p.OverlayBuild
|
||||
path = newPath
|
||||
}
|
||||
cmd, err := List(config, extraArgs, inputPkgs)
|
||||
buildPkg, err := ctx.Import(path, srcDir, build.ImportComment)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf := &bytes.Buffer{}
|
||||
cmd.Stdout = buf
|
||||
cmd.Stderr = os.Stderr
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
|
||||
os.Exit(status.ExitStatus())
|
||||
}
|
||||
os.Exit(1)
|
||||
return nil, scanner.Error{
|
||||
Pos: pos,
|
||||
Msg: err.Error(), // TODO: define a new error type that will wrap the inner error
|
||||
}
|
||||
return nil, fmt.Errorf("failed to run `go list`: %s", err)
|
||||
}
|
||||
if existingPkg, ok := p.Packages[buildPkg.ImportPath]; ok {
|
||||
// Already imported, or at least started the import.
|
||||
return existingPkg, nil
|
||||
}
|
||||
p.sorted = nil // invalidate the sorted order of packages
|
||||
pkg := p.newPackage(buildPkg)
|
||||
p.Packages[buildPkg.ImportPath] = pkg
|
||||
|
||||
if p.mainPkg == "" {
|
||||
p.mainPkg = buildPkg.ImportPath
|
||||
}
|
||||
|
||||
// Parse the returned json from `go list`.
|
||||
decoder := json.NewDecoder(buf)
|
||||
for {
|
||||
pkg := &Package{
|
||||
program: p,
|
||||
info: types.Info{
|
||||
Types: make(map[ast.Expr]types.TypeAndValue),
|
||||
Defs: make(map[*ast.Ident]types.Object),
|
||||
Uses: make(map[*ast.Ident]types.Object),
|
||||
Implicits: make(map[ast.Node]types.Object),
|
||||
Scopes: make(map[ast.Node]*types.Scope),
|
||||
Selections: make(map[*ast.SelectorExpr]*types.Selection),
|
||||
},
|
||||
}
|
||||
err := decoder.Decode(&pkg.PackageJSON)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if pkg.Error != nil {
|
||||
// There was an error while importing (for example, a circular
|
||||
// dependency).
|
||||
pos := token.Position{}
|
||||
fields := strings.Split(pkg.Error.Pos, ":")
|
||||
if len(fields) >= 2 {
|
||||
// There is some file/line/column information.
|
||||
if n, err := strconv.Atoi(fields[len(fields)-2]); err == nil {
|
||||
// Format: filename.go:line:colum
|
||||
pos.Filename = strings.Join(fields[:len(fields)-2], ":")
|
||||
pos.Line = n
|
||||
pos.Column, _ = strconv.Atoi(fields[len(fields)-1])
|
||||
} else {
|
||||
// Format: filename.go:line
|
||||
pos.Filename = strings.Join(fields[:len(fields)-1], ":")
|
||||
pos.Line, _ = strconv.Atoi(fields[len(fields)-1])
|
||||
}
|
||||
pos.Filename = p.getOriginalPath(pos.Filename)
|
||||
}
|
||||
err := scanner.Error{
|
||||
Pos: pos,
|
||||
Msg: pkg.Error.Err,
|
||||
}
|
||||
if len(pkg.Error.ImportStack) != 0 {
|
||||
return nil, Error{
|
||||
ImportStack: pkg.Error.ImportStack,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if config.TestConfig.CompileTestBinary {
|
||||
// When creating a test binary, `go list` will list two or three
|
||||
// packages used for testing the package. The first is the original
|
||||
// package as if it were built normally, the second is the same
|
||||
// package but with the *_test.go files included. A possible third
|
||||
// may be included for _test packages (such as math_test), used to
|
||||
// test the external API with no access to internal functions.
|
||||
// All packages that are necessary for testing (including the to be
|
||||
// tested package with *_test.go files, but excluding the original
|
||||
// unmodified package) have a suffix added to the import path, for
|
||||
// example the math package has import path "math [math.test]" and
|
||||
// test dependencies such as fmt will have an import path of the
|
||||
// form "fmt [math.test]".
|
||||
// The code below removes this suffix, and if this results in a
|
||||
// duplicate (which happens with the to-be-tested package without
|
||||
// *.test.go files) the previous package is removed from the list of
|
||||
// packages included in this build.
|
||||
// This is necessary because the change in import paths results in
|
||||
// breakage to //go:linkname. Additionally, the duplicated package
|
||||
// slows down the build and so is best removed.
|
||||
if pkg.ForTest != "" && strings.HasSuffix(pkg.ImportPath, " ["+pkg.ForTest+".test]") {
|
||||
newImportPath := pkg.ImportPath[:len(pkg.ImportPath)-len(" ["+pkg.ForTest+".test]")]
|
||||
if _, ok := p.Packages[newImportPath]; ok {
|
||||
// Delete the previous package (that this package overrides).
|
||||
delete(p.Packages, newImportPath)
|
||||
for i, pkg := range p.sorted {
|
||||
if pkg.ImportPath == newImportPath {
|
||||
p.sorted = append(p.sorted[:i], p.sorted[i+1:]...) // remove element from slice
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
pkg.ImportPath = newImportPath
|
||||
}
|
||||
}
|
||||
p.sorted = append(p.sorted, pkg)
|
||||
p.Packages[pkg.ImportPath] = pkg
|
||||
}
|
||||
|
||||
return p, nil
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
// getOriginalPath looks whether this path is in the generated GOROOT and if so,
|
||||
// replaces the path with the original path (in GOROOT or TINYGOROOT). Otherwise
|
||||
// the input path is returned.
|
||||
func (p *Program) getOriginalPath(path string) string {
|
||||
originalPath := path
|
||||
if strings.HasPrefix(path, p.goroot+string(filepath.Separator)) {
|
||||
// If this file is part of the synthetic GOROOT, try to infer the
|
||||
// original path.
|
||||
relpath := path[len(filepath.Join(p.goroot, "src"))+1:]
|
||||
realgorootPath := filepath.Join(goenv.Get("GOROOT"), "src", relpath)
|
||||
if _, err := os.Stat(realgorootPath); err == nil {
|
||||
originalPath = realgorootPath
|
||||
}
|
||||
maybeInTinyGoRoot := false
|
||||
for prefix := range pathsToOverride(needsSyscallPackage(p.config.BuildTags())) {
|
||||
if !strings.HasPrefix(relpath, prefix) {
|
||||
continue
|
||||
}
|
||||
maybeInTinyGoRoot = true
|
||||
}
|
||||
if maybeInTinyGoRoot {
|
||||
tinygoPath := filepath.Join(goenv.Get("TINYGOROOT"), "src", relpath)
|
||||
if _, err := os.Stat(tinygoPath); err == nil {
|
||||
originalPath = tinygoPath
|
||||
}
|
||||
}
|
||||
// ImportFile loads and parses the import statements in the given path and
|
||||
// creates a pseudo-package out of it.
|
||||
func (p *Program) ImportFile(path string) (*Package, error) {
|
||||
if p.Packages == nil {
|
||||
p.Packages = make(map[string]*Package)
|
||||
}
|
||||
if _, ok := p.Packages[path]; ok {
|
||||
// unlikely
|
||||
return nil, errors.New("loader: cannot import file that is already imported as package: " + path)
|
||||
}
|
||||
|
||||
file, err := p.parseFile(path, parser.ImportsOnly)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buildPkg := &build.Package{
|
||||
Dir: filepath.Dir(path),
|
||||
ImportPath: path,
|
||||
GoFiles: []string{filepath.Base(path)},
|
||||
}
|
||||
for _, importSpec := range file.Imports {
|
||||
buildPkg.Imports = append(buildPkg.Imports, importSpec.Path.Value[1:len(importSpec.Path.Value)-1])
|
||||
}
|
||||
p.sorted = nil // invalidate the sorted order of packages
|
||||
pkg := p.newPackage(buildPkg)
|
||||
p.Packages[buildPkg.ImportPath] = pkg
|
||||
|
||||
if p.mainPkg == "" {
|
||||
p.mainPkg = buildPkg.ImportPath
|
||||
}
|
||||
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
// newPackage instantiates a new *Package object with initialized members.
|
||||
func (p *Program) newPackage(pkg *build.Package) *Package {
|
||||
return &Package{
|
||||
Program: p,
|
||||
Package: pkg,
|
||||
Imports: make(map[string]*Package, len(pkg.Imports)),
|
||||
Info: types.Info{
|
||||
Types: make(map[ast.Expr]types.TypeAndValue),
|
||||
Defs: make(map[*ast.Ident]types.Object),
|
||||
Uses: make(map[*ast.Ident]types.Object),
|
||||
Implicits: make(map[ast.Node]types.Object),
|
||||
Scopes: make(map[ast.Node]*types.Scope),
|
||||
Selections: make(map[*ast.SelectorExpr]*types.Selection),
|
||||
},
|
||||
}
|
||||
return originalPath
|
||||
}
|
||||
|
||||
// Sorted returns a list of all packages, sorted in a way that no packages come
|
||||
// before the packages they depend upon.
|
||||
func (p *Program) Sorted() []*Package {
|
||||
if p.sorted == nil {
|
||||
p.sort()
|
||||
}
|
||||
return p.sorted
|
||||
}
|
||||
|
||||
// MainPkg returns the last package in the Sorted() slice. This is the main
|
||||
// package of the program.
|
||||
func (p *Program) MainPkg() *Package {
|
||||
return p.sorted[len(p.sorted)-1]
|
||||
func (p *Program) sort() {
|
||||
p.sorted = nil
|
||||
packageList := make([]*Package, 0, len(p.Packages))
|
||||
packageSet := make(map[string]struct{}, len(p.Packages))
|
||||
worklist := make([]string, 0, len(p.Packages))
|
||||
for path := range p.Packages {
|
||||
worklist = append(worklist, path)
|
||||
}
|
||||
sort.Strings(worklist)
|
||||
for len(worklist) != 0 {
|
||||
pkgPath := worklist[0]
|
||||
pkg := p.Packages[pkgPath]
|
||||
|
||||
if _, ok := packageSet[pkgPath]; ok {
|
||||
// Package already in the final package list.
|
||||
worklist = worklist[1:]
|
||||
continue
|
||||
}
|
||||
|
||||
unsatisfiedImports := make([]string, 0)
|
||||
for _, pkg := range pkg.Imports {
|
||||
if _, ok := packageSet[pkg.ImportPath]; ok {
|
||||
continue
|
||||
}
|
||||
unsatisfiedImports = append(unsatisfiedImports, pkg.ImportPath)
|
||||
}
|
||||
sort.Strings(unsatisfiedImports)
|
||||
if len(unsatisfiedImports) == 0 {
|
||||
// All dependencies of this package are satisfied, so add this
|
||||
// package to the list.
|
||||
packageList = append(packageList, pkg)
|
||||
packageSet[pkgPath] = struct{}{}
|
||||
worklist = worklist[1:]
|
||||
} else {
|
||||
// Prepend all dependencies to the worklist and reconsider this
|
||||
// package (by not removing it from the worklist). At that point, it
|
||||
// must be possible to add it to packageList.
|
||||
worklist = append(unsatisfiedImports, worklist...)
|
||||
}
|
||||
}
|
||||
|
||||
p.sorted = packageList
|
||||
}
|
||||
|
||||
// Parse parses all packages and typechecks them.
|
||||
// Parse recursively imports all packages, parses them, and typechecks them.
|
||||
//
|
||||
// The returned error may be an Errors error, which contains a list of errors.
|
||||
//
|
||||
// Idempotent.
|
||||
func (p *Program) Parse() error {
|
||||
func (p *Program) Parse(compileTestBinary bool) error {
|
||||
includeTests := compileTestBinary
|
||||
|
||||
// Load all imports
|
||||
for _, pkg := range p.Sorted() {
|
||||
err := pkg.importRecursively(includeTests)
|
||||
if err != nil {
|
||||
if err, ok := err.(*ImportCycleError); ok {
|
||||
if pkg.ImportPath != err.Packages[0] {
|
||||
err.Packages = append([]string{pkg.ImportPath}, err.Packages...)
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Parse all packages.
|
||||
// TODO: do this in parallel.
|
||||
for _, pkg := range p.sorted {
|
||||
err := pkg.Parse()
|
||||
for _, pkg := range p.Sorted() {
|
||||
err := pkg.Parse(includeTests)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if compileTestBinary {
|
||||
err := p.SwapTestMain()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Typecheck all packages.
|
||||
for _, pkg := range p.sorted {
|
||||
for _, pkg := range p.Sorted() {
|
||||
err := pkg.Check()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -278,6 +231,83 @@ func (p *Program) Parse() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Program) SwapTestMain() error {
|
||||
var tests []string
|
||||
|
||||
isTestFunc := func(f *ast.FuncDecl) bool {
|
||||
// TODO: improve signature check
|
||||
if strings.HasPrefix(f.Name.Name, "Test") && f.Name.Name != "TestMain" {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
mainPkg := p.Packages[p.mainPkg]
|
||||
for _, f := range mainPkg.Files {
|
||||
for i, d := range f.Decls {
|
||||
switch v := d.(type) {
|
||||
case *ast.FuncDecl:
|
||||
if isTestFunc(v) {
|
||||
tests = append(tests, v.Name.Name)
|
||||
}
|
||||
if v.Name.Name == "main" {
|
||||
// Remove main
|
||||
if len(f.Decls) == 1 {
|
||||
f.Decls = make([]ast.Decl, 0)
|
||||
} else {
|
||||
f.Decls[i] = f.Decls[len(f.Decls)-1]
|
||||
f.Decls = f.Decls[:len(f.Decls)-1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Check if they defined a TestMain and call it instead of testing.TestMain
|
||||
const mainBody = `package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func main () {
|
||||
m := &testing.M{
|
||||
Tests: []testing.TestToCall{
|
||||
{{range .TestFunctions}}
|
||||
{Name: "{{.}}", Func: {{.}}},
|
||||
{{end}}
|
||||
},
|
||||
}
|
||||
|
||||
testing.TestMain(m)
|
||||
}
|
||||
`
|
||||
tmpl := template.Must(template.New("testmain").Parse(mainBody))
|
||||
b := bytes.Buffer{}
|
||||
tmplData := struct {
|
||||
TestFunctions []string
|
||||
}{
|
||||
TestFunctions: tests,
|
||||
}
|
||||
|
||||
err := tmpl.Execute(&b, tmplData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
path := filepath.Join(p.mainPkg, "$testmain.go")
|
||||
|
||||
if p.fset == nil {
|
||||
p.fset = token.NewFileSet()
|
||||
}
|
||||
|
||||
newMain, err := parser.ParseFile(p.fset, path, b.Bytes(), parser.AllErrors)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
mainPkg.Files = append(mainPkg.Files, newMain)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseFile is a wrapper around parser.ParseFile.
|
||||
func (p *Program) parseFile(path string, mode parser.Mode) (*ast.File, error) {
|
||||
if p.fset == nil {
|
||||
@@ -289,26 +319,34 @@ func (p *Program) parseFile(path string, mode parser.Mode) (*ast.File, error) {
|
||||
return nil, err
|
||||
}
|
||||
defer rd.Close()
|
||||
return parser.ParseFile(p.fset, p.getOriginalPath(path), rd, mode)
|
||||
relpath := path
|
||||
if filepath.IsAbs(path) {
|
||||
rp, err := filepath.Rel(p.Dir, path)
|
||||
if err == nil {
|
||||
relpath = rp
|
||||
}
|
||||
}
|
||||
return parser.ParseFile(p.fset, relpath, rd, mode)
|
||||
}
|
||||
|
||||
// Parse parses and typechecks this package.
|
||||
//
|
||||
// Idempotent.
|
||||
func (p *Package) Parse() error {
|
||||
func (p *Package) Parse(includeTests bool) error {
|
||||
if len(p.Files) != 0 {
|
||||
return nil // nothing to do (?)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Load the AST.
|
||||
// TODO: do this in parallel.
|
||||
if p.ImportPath == "unsafe" {
|
||||
// Special case for the unsafe package, which is defined internally by
|
||||
// the types package.
|
||||
// Special case for the unsafe package. Don't even bother loading
|
||||
// the files.
|
||||
p.Pkg = types.Unsafe
|
||||
return nil
|
||||
}
|
||||
|
||||
files, err := p.parseFiles()
|
||||
files, err := p.parseFiles(includeTests)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -323,11 +361,11 @@ func (p *Package) Parse() error {
|
||||
// Idempotent.
|
||||
func (p *Package) Check() error {
|
||||
if p.Pkg != nil {
|
||||
return nil // already typechecked
|
||||
return nil
|
||||
}
|
||||
|
||||
var typeErrors []error
|
||||
checker := p.program.typeChecker // make a copy, because it will be modified
|
||||
checker := p.TypeChecker
|
||||
checker.Error = func(err error) {
|
||||
typeErrors = append(typeErrors, err)
|
||||
}
|
||||
@@ -335,7 +373,7 @@ func (p *Package) Check() error {
|
||||
// Do typechecking of the package.
|
||||
checker.Importer = p
|
||||
|
||||
typesPkg, err := checker.Check(p.ImportPath, p.program.fset, p.Files, &p.info)
|
||||
typesPkg, err := checker.Check(p.ImportPath, p.fset, p.Files, &p.Info)
|
||||
if err != nil {
|
||||
if err, ok := err.(Errors); ok {
|
||||
return err
|
||||
@@ -347,47 +385,52 @@ func (p *Package) Check() error {
|
||||
}
|
||||
|
||||
// parseFiles parses the loaded list of files and returns this list.
|
||||
func (p *Package) parseFiles() ([]*ast.File, error) {
|
||||
func (p *Package) parseFiles(includeTests bool) ([]*ast.File, error) {
|
||||
// TODO: do this concurrently.
|
||||
var files []*ast.File
|
||||
var fileErrs []error
|
||||
|
||||
// Parse all files (incuding CgoFiles).
|
||||
parseFile := func(file string) {
|
||||
if !filepath.IsAbs(file) {
|
||||
file = filepath.Join(p.Dir, file)
|
||||
}
|
||||
f, err := p.program.parseFile(file, parser.ParseComments)
|
||||
var gofiles []string
|
||||
if includeTests {
|
||||
gofiles = make([]string, 0, len(p.GoFiles)+len(p.TestGoFiles))
|
||||
gofiles = append(gofiles, p.GoFiles...)
|
||||
gofiles = append(gofiles, p.TestGoFiles...)
|
||||
} else {
|
||||
gofiles = p.GoFiles
|
||||
}
|
||||
|
||||
for _, file := range gofiles {
|
||||
f, err := p.parseFile(filepath.Join(p.Package.Dir, file), parser.ParseComments)
|
||||
if err != nil {
|
||||
fileErrs = append(fileErrs, err)
|
||||
return
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
fileErrs = append(fileErrs, err)
|
||||
continue
|
||||
}
|
||||
files = append(files, f)
|
||||
}
|
||||
for _, file := range p.GoFiles {
|
||||
parseFile(file)
|
||||
}
|
||||
for _, file := range p.CgoFiles {
|
||||
parseFile(file)
|
||||
}
|
||||
|
||||
// Do CGo processing.
|
||||
if len(p.CgoFiles) != 0 {
|
||||
var cflags []string
|
||||
cflags = append(cflags, p.program.config.CFlags()...)
|
||||
cflags = append(cflags, "-I"+p.Dir)
|
||||
if p.program.clangHeaders != "" {
|
||||
cflags = append(cflags, "-Xclang", "-internal-isystem", "-Xclang", p.program.clangHeaders)
|
||||
path := filepath.Join(p.Package.Dir, file)
|
||||
f, err := p.parseFile(path, parser.ParseComments)
|
||||
if err != nil {
|
||||
fileErrs = append(fileErrs, err)
|
||||
continue
|
||||
}
|
||||
generated, ldflags, errs := cgo.Process(files, p.program.workingDir, p.program.fset, cflags)
|
||||
files = append(files, f)
|
||||
}
|
||||
if len(p.CgoFiles) != 0 {
|
||||
cflags := append(p.CFlags, "-I"+p.Package.Dir)
|
||||
if p.ClangHeaders != "" {
|
||||
cflags = append(cflags, "-Xclang", "-internal-isystem", "-Xclang", p.ClangHeaders)
|
||||
}
|
||||
generated, errs := cgo.Process(files, p.Program.Dir, p.fset, cflags)
|
||||
if errs != nil {
|
||||
fileErrs = append(fileErrs, errs...)
|
||||
}
|
||||
files = append(files, generated)
|
||||
p.program.LDFlags = append(p.program.LDFlags, ldflags...)
|
||||
}
|
||||
|
||||
// Only return an error after CGo processing, so that errors in parsing and
|
||||
// CGo can be reported together.
|
||||
if len(fileErrs) != 0 {
|
||||
return nil, Errors{p, fileErrs}
|
||||
}
|
||||
@@ -401,9 +444,59 @@ func (p *Package) Import(to string) (*types.Package, error) {
|
||||
if to == "unsafe" {
|
||||
return types.Unsafe, nil
|
||||
}
|
||||
if imported, ok := p.program.Packages[to]; ok {
|
||||
return imported.Pkg, nil
|
||||
if _, ok := p.Imports[to]; ok {
|
||||
return p.Imports[to].Pkg, nil
|
||||
} else {
|
||||
return nil, errors.New("package not imported: " + to)
|
||||
}
|
||||
}
|
||||
|
||||
// importRecursively calls Program.Import() on all imported packages, and calls
|
||||
// importRecursively() on the imported packages as well.
|
||||
//
|
||||
// Idempotent.
|
||||
func (p *Package) importRecursively(includeTests bool) error {
|
||||
p.Importing = true
|
||||
|
||||
imports := p.Package.Imports
|
||||
if includeTests {
|
||||
imports = append(imports, p.Package.TestImports...)
|
||||
}
|
||||
|
||||
for _, to := range imports {
|
||||
if to == "C" {
|
||||
// Do CGo processing in a later stage.
|
||||
continue
|
||||
}
|
||||
if _, ok := p.Imports[to]; ok {
|
||||
continue
|
||||
}
|
||||
// Find error location.
|
||||
var pos token.Position
|
||||
if len(p.Package.ImportPos[to]) > 0 {
|
||||
pos = p.Package.ImportPos[to][0]
|
||||
} else {
|
||||
pos = token.Position{Filename: p.Package.ImportPath}
|
||||
}
|
||||
importedPkg, err := p.Program.Import(to, p.Package.Dir, pos)
|
||||
if err != nil {
|
||||
if err, ok := err.(*ImportCycleError); ok {
|
||||
err.Packages = append([]string{p.ImportPath}, err.Packages...)
|
||||
}
|
||||
return err
|
||||
}
|
||||
if importedPkg.Importing {
|
||||
return &ImportCycleError{[]string{p.ImportPath, importedPkg.ImportPath}, p.ImportPos[to]}
|
||||
}
|
||||
err = importedPkg.importRecursively(false)
|
||||
if err != nil {
|
||||
if err, ok := err.(*ImportCycleError); ok {
|
||||
err.Packages = append([]string{p.ImportPath}, err.Packages...)
|
||||
}
|
||||
return err
|
||||
}
|
||||
p.Imports[to] = importedPkg
|
||||
}
|
||||
p.Importing = false
|
||||
return nil
|
||||
}
|
||||
|
||||
+2
-2
@@ -10,8 +10,8 @@ import (
|
||||
func (p *Program) LoadSSA() *ssa.Program {
|
||||
prog := ssa.NewProgram(p.fset, ssa.SanityCheckFunctions|ssa.BareInits|ssa.GlobalDebug)
|
||||
|
||||
for _, pkg := range p.sorted {
|
||||
prog.CreatePackage(pkg.Pkg, pkg.Files, &pkg.info, true)
|
||||
for _, pkg := range p.Sorted() {
|
||||
prog.CreatePackage(pkg.Pkg, pkg.Files, &pkg.Info, true)
|
||||
}
|
||||
|
||||
return prog
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"go/scanner"
|
||||
"go/types"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
@@ -29,12 +28,6 @@ import (
|
||||
"go.bug.st/serial"
|
||||
)
|
||||
|
||||
var (
|
||||
// This variable is set at build time using -ldflags parameters.
|
||||
// See: https://stackoverflow.com/a/11355611
|
||||
gitSha1 string
|
||||
)
|
||||
|
||||
// commandError is an error type to wrap os/exec.Command errors. This provides
|
||||
// some more information regarding what went wrong while running a command.
|
||||
type commandError struct {
|
||||
@@ -65,28 +58,33 @@ func moveFile(src, dst string) error {
|
||||
return os.Remove(src)
|
||||
}
|
||||
|
||||
// copyFile copies the given file from src to dst. It can copy over
|
||||
// a possibly already existing file at the destination.
|
||||
// copyFile copies the given file from src to dst. It copies first to a .tmp
|
||||
// file which is then moved over a possibly already existing file at the
|
||||
// destination.
|
||||
func copyFile(src, dst string) error {
|
||||
source, err := os.Open(src)
|
||||
inf, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer source.Close()
|
||||
|
||||
st, err := source.Stat()
|
||||
defer inf.Close()
|
||||
outpath := dst + ".tmp"
|
||||
outf, err := os.Create(outpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
destination, err := os.OpenFile(dst, os.O_RDWR|os.O_CREATE|os.O_TRUNC, st.Mode())
|
||||
_, err = io.Copy(outf, inf)
|
||||
if err != nil {
|
||||
os.Remove(outpath)
|
||||
return err
|
||||
}
|
||||
|
||||
err = outf.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destination.Close()
|
||||
|
||||
_, err = io.Copy(destination, source)
|
||||
return err
|
||||
return os.Rename(dst+".tmp", dst)
|
||||
}
|
||||
|
||||
// Build compiles and links the given package and writes it to outpath.
|
||||
@@ -96,10 +94,10 @@ func Build(pkgName, outpath string, options *compileopts.Options) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error {
|
||||
if err := os.Rename(result.Binary, outpath); err != nil {
|
||||
return builder.Build(pkgName, outpath, config, func(tmppath string) error {
|
||||
if err := os.Rename(tmppath, outpath); err != nil {
|
||||
// Moving failed. Do a file copy.
|
||||
inf, err := os.Open(result.Binary)
|
||||
inf, err := os.Open(tmppath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -125,71 +123,35 @@ func Build(pkgName, outpath string, options *compileopts.Options) error {
|
||||
}
|
||||
|
||||
// Test runs the tests in the given package.
|
||||
func Test(pkgName string, options *compileopts.Options, testCompileOnly bool, outpath string) error {
|
||||
options.TestConfig.CompileTestBinary = true
|
||||
func Test(pkgName string, options *compileopts.Options) error {
|
||||
config, err := builder.NewConfig(options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error {
|
||||
if testCompileOnly || outpath != "" {
|
||||
// Write test binary to the specified file name.
|
||||
if outpath == "" {
|
||||
// No -o path was given, so create one now.
|
||||
// This matches the behavior of go test.
|
||||
outpath = filepath.Base(result.MainDir) + ".test"
|
||||
}
|
||||
copyFile(result.Binary, outpath)
|
||||
}
|
||||
if testCompileOnly {
|
||||
// Do not run the test.
|
||||
return nil
|
||||
}
|
||||
if len(config.Target.Emulator) == 0 {
|
||||
// Run directly.
|
||||
cmd := exec.Command(result.Binary)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Dir = result.MainDir
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
// Propagate the exit code
|
||||
if err, ok := err.(*exec.ExitError); ok {
|
||||
if status, ok := err.Sys().(syscall.WaitStatus); ok {
|
||||
os.Exit(status.ExitStatus())
|
||||
}
|
||||
os.Exit(1)
|
||||
// Add test build tag. This is incorrect: `go test` only looks at the
|
||||
// _test.go file suffix but does not add the test build tag in the process.
|
||||
// However, it's a simple fix right now.
|
||||
// For details: https://github.com/golang/go/issues/21360
|
||||
config.Target.BuildTags = append(config.Target.BuildTags, "test")
|
||||
|
||||
options.TestConfig.CompileTestBinary = true
|
||||
return builder.Build(pkgName, ".elf", config, func(tmppath string) error {
|
||||
cmd := exec.Command(tmppath)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
// Propagate the exit code
|
||||
if err, ok := err.(*exec.ExitError); ok {
|
||||
if status, ok := err.Sys().(syscall.WaitStatus); ok {
|
||||
os.Exit(status.ExitStatus())
|
||||
}
|
||||
return &commandError{"failed to run compiled binary", result.Binary, err}
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
// Run in an emulator.
|
||||
args := append(config.Target.Emulator[1:], result.Binary)
|
||||
cmd := exec.Command(config.Target.Emulator[0], args...)
|
||||
buf := &bytes.Buffer{}
|
||||
w := io.MultiWriter(os.Stdout, buf)
|
||||
cmd.Stdout = w
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
if err, ok := err.(*exec.ExitError); !ok || !err.Exited() {
|
||||
// Workaround for QEMU which always exits with an error.
|
||||
return &commandError{"failed to run emulator with", result.Binary, err}
|
||||
}
|
||||
}
|
||||
testOutput := string(buf.Bytes())
|
||||
if testOutput == "PASS\n" || strings.HasSuffix(testOutput, "\nPASS\n") {
|
||||
// Test passed.
|
||||
return nil
|
||||
} else {
|
||||
// Test failed, either by ending with the word "FAIL" or with a
|
||||
// panic of some sort.
|
||||
os.Exit(1)
|
||||
return nil // unreachable
|
||||
}
|
||||
return &commandError{"failed to run compiled binary", tmppath, err}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
@@ -231,9 +193,9 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
return errors.New("unknown flash method: " + flashMethod)
|
||||
}
|
||||
|
||||
return builder.Build(pkgName, fileExt, config, func(result builder.BuildResult) error {
|
||||
return builder.Build(pkgName, fileExt, config, func(tmppath string) error {
|
||||
// do we need port reset to put MCU into bootloader mode?
|
||||
if config.Target.PortReset == "true" && flashMethod != "openocd" {
|
||||
if config.Target.PortReset == "true" {
|
||||
if port == "" {
|
||||
var err error
|
||||
port, err = getDefaultPort()
|
||||
@@ -244,7 +206,7 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
|
||||
err := touchSerialPortAt1200bps(port)
|
||||
if err != nil {
|
||||
return &commandError{"failed to reset port", result.Binary, err}
|
||||
return &commandError{"failed to reset port", tmppath, err}
|
||||
}
|
||||
// give the target MCU a chance to restart into bootloader
|
||||
time.Sleep(3 * time.Second)
|
||||
@@ -256,7 +218,7 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
// Create the command.
|
||||
flashCmd := config.Target.FlashCommand
|
||||
fileToken := "{" + fileExt[1:] + "}"
|
||||
flashCmd = strings.Replace(flashCmd, fileToken, result.Binary, -1)
|
||||
flashCmd = strings.Replace(flashCmd, fileToken, tmppath, -1)
|
||||
|
||||
if port == "" && strings.Contains(flashCmd, "{port}") {
|
||||
var err error
|
||||
@@ -286,21 +248,21 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
cmd.Dir = goenv.Get("TINYGOROOT")
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
return &commandError{"failed to flash", tmppath, err}
|
||||
}
|
||||
return nil
|
||||
case "msd":
|
||||
switch fileExt {
|
||||
case ".uf2":
|
||||
err := flashUF2UsingMSD(config.Target.FlashVolume, result.Binary)
|
||||
err := flashUF2UsingMSD(config.Target.FlashVolume, tmppath)
|
||||
if err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
return &commandError{"failed to flash", tmppath, err}
|
||||
}
|
||||
return nil
|
||||
case ".hex":
|
||||
err := flashHexUsingMSD(config.Target.FlashVolume, result.Binary)
|
||||
err := flashHexUsingMSD(config.Target.FlashVolume, tmppath)
|
||||
if err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
return &commandError{"failed to flash", tmppath, err}
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
@@ -311,13 +273,13 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
args = append(args, "-c", "program "+filepath.ToSlash(result.Binary)+" reset exit")
|
||||
args = append(args, "-c", "program "+tmppath+" reset exit")
|
||||
cmd := exec.Command("openocd", args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return &commandError{"failed to flash", result.Binary, err}
|
||||
return &commandError{"failed to flash", tmppath, err}
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
@@ -342,7 +304,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
|
||||
return errors.New("gdb not configured in the target specification")
|
||||
}
|
||||
|
||||
return builder.Build(pkgName, "", config, func(result builder.BuildResult) error {
|
||||
return builder.Build(pkgName, "", config, func(tmppath string) error {
|
||||
// Find a good way to run GDB.
|
||||
gdbInterface, openocdInterface := config.Programmer()
|
||||
switch gdbInterface {
|
||||
@@ -351,17 +313,13 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
|
||||
// Assume QEMU as an emulator.
|
||||
if config.Target.Emulator[0] == "mgba" {
|
||||
gdbInterface = "mgba"
|
||||
} else if strings.HasPrefix(config.Target.Emulator[0], "qemu-system-") {
|
||||
gdbInterface = "qemu"
|
||||
} else {
|
||||
gdbInterface = "qemu-user"
|
||||
gdbInterface = "qemu"
|
||||
}
|
||||
} else if openocdInterface != "" && config.Target.OpenOCDTarget != "" {
|
||||
gdbInterface = "openocd"
|
||||
} else if config.Target.JLinkDevice != "" {
|
||||
gdbInterface = "jlink"
|
||||
} else {
|
||||
gdbInterface = "native"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,15 +367,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
|
||||
gdbCommands = append(gdbCommands, "target remote :1234")
|
||||
|
||||
// Run in an emulator.
|
||||
args := append(config.Target.Emulator[1:], result.Binary, "-s", "-S")
|
||||
daemon = exec.Command(config.Target.Emulator[0], args...)
|
||||
daemon.Stdout = os.Stdout
|
||||
daemon.Stderr = os.Stderr
|
||||
case "qemu-user":
|
||||
gdbCommands = append(gdbCommands, "target remote :1234")
|
||||
|
||||
// Run in an emulator.
|
||||
args := append(config.Target.Emulator[1:], "-g", "1234", result.Binary)
|
||||
args := append(config.Target.Emulator[1:], tmppath, "-s", "-S")
|
||||
daemon = exec.Command(config.Target.Emulator[0], args...)
|
||||
daemon.Stdout = os.Stdout
|
||||
daemon.Stderr = os.Stderr
|
||||
@@ -425,7 +375,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
|
||||
gdbCommands = append(gdbCommands, "target remote :2345")
|
||||
|
||||
// Run in an emulator.
|
||||
args := append(config.Target.Emulator[1:], result.Binary, "-g")
|
||||
args := append(config.Target.Emulator[1:], tmppath, "-g")
|
||||
daemon = exec.Command(config.Target.Emulator[0], args...)
|
||||
daemon.Stdout = os.Stdout
|
||||
daemon.Stderr = os.Stderr
|
||||
@@ -463,7 +413,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
|
||||
// Construct and execute a gdb command.
|
||||
// By default: gdb -ex run <binary>
|
||||
// Exit GDB with Ctrl-D.
|
||||
params := []string{result.Binary}
|
||||
params := []string{tmppath}
|
||||
for _, cmd := range gdbCommands {
|
||||
params = append(params, "-ex", cmd)
|
||||
}
|
||||
@@ -473,7 +423,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return &commandError{"failed to run gdb with", result.Binary, err}
|
||||
return &commandError{"failed to run gdb with", tmppath, err}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
@@ -489,10 +439,10 @@ func Run(pkgName string, options *compileopts.Options) error {
|
||||
return err
|
||||
}
|
||||
|
||||
return builder.Build(pkgName, ".elf", config, func(result builder.BuildResult) error {
|
||||
return builder.Build(pkgName, ".elf", config, func(tmppath string) error {
|
||||
if len(config.Target.Emulator) == 0 {
|
||||
// Run directly.
|
||||
cmd := exec.Command(result.Binary)
|
||||
cmd := exec.Command(tmppath)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
@@ -501,12 +451,12 @@ func Run(pkgName string, options *compileopts.Options) error {
|
||||
// Workaround for QEMU which always exits with an error.
|
||||
return nil
|
||||
}
|
||||
return &commandError{"failed to run compiled binary", result.Binary, err}
|
||||
return &commandError{"failed to run compiled binary", tmppath, err}
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
// Run in an emulator.
|
||||
args := append(config.Target.Emulator[1:], result.Binary)
|
||||
args := append(config.Target.Emulator[1:], tmppath)
|
||||
cmd := exec.Command(config.Target.Emulator[0], args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
@@ -516,7 +466,7 @@ func Run(pkgName string, options *compileopts.Options) error {
|
||||
// Workaround for QEMU which always exits with an error.
|
||||
return nil
|
||||
}
|
||||
return &commandError{"failed to run emulator with", result.Binary, err}
|
||||
return &commandError{"failed to run emulator with", tmppath, err}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -529,13 +479,6 @@ func touchSerialPortAt1200bps(port string) (err error) {
|
||||
// Open port
|
||||
p, e := serial.Open(port, &serial.Mode{BaudRate: 1200})
|
||||
if e != nil {
|
||||
if runtime.GOOS == `windows` {
|
||||
se, ok := e.(*serial.PortError)
|
||||
if ok && se.Code() == serial.InvalidSerialPort {
|
||||
// InvalidSerialPort error occurs when transitioning to boot
|
||||
return nil
|
||||
}
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
err = e
|
||||
continue
|
||||
@@ -548,8 +491,6 @@ func touchSerialPortAt1200bps(port string) (err error) {
|
||||
return fmt.Errorf("opening port: %s", err)
|
||||
}
|
||||
|
||||
const maxMSDRetries = 10
|
||||
|
||||
func flashUF2UsingMSD(volume, tmppath string) error {
|
||||
// find standard UF2 info path
|
||||
var infoPath string
|
||||
@@ -566,12 +507,15 @@ func flashUF2UsingMSD(volume, tmppath string) error {
|
||||
infoPath = path + "/INFO_UF2.TXT"
|
||||
}
|
||||
|
||||
d, err := locateDevice(volume, infoPath)
|
||||
d, err := filepath.Glob(infoPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d == nil {
|
||||
return errors.New("unable to locate UF2 device: " + volume)
|
||||
}
|
||||
|
||||
return moveFile(tmppath, filepath.Dir(d)+"/flash.uf2")
|
||||
return moveFile(tmppath, filepath.Dir(d[0])+"/flash.uf2")
|
||||
}
|
||||
|
||||
func flashHexUsingMSD(volume, tmppath string) error {
|
||||
@@ -590,31 +534,15 @@ func flashHexUsingMSD(volume, tmppath string) error {
|
||||
destPath = path + "/"
|
||||
}
|
||||
|
||||
d, err := locateDevice(volume, destPath)
|
||||
d, err := filepath.Glob(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return moveFile(tmppath, d+"/flash.hex")
|
||||
}
|
||||
|
||||
func locateDevice(volume, path string) (string, error) {
|
||||
var d []string
|
||||
var err error
|
||||
for i := 0; i < maxMSDRetries; i++ {
|
||||
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 errors.New("unable to locate device: " + volume)
|
||||
}
|
||||
return d[0], nil
|
||||
|
||||
return moveFile(tmppath, d[0]+"/flash.hex")
|
||||
}
|
||||
|
||||
func windowsFindUSBDrive(volume string) (string, error) {
|
||||
@@ -675,18 +603,29 @@ func getDefaultPort() (port string, err error) {
|
||||
case "freebsd":
|
||||
portPath = "/dev/cuaU*"
|
||||
case "windows":
|
||||
ports, err := serial.GetPortsList()
|
||||
cmd := exec.Command("wmic",
|
||||
"PATH", "Win32_SerialPort", "WHERE", "Caption LIKE 'USB Serial%'", "GET", "DeviceID")
|
||||
|
||||
var out bytes.Buffer
|
||||
cmd.Stdout = &out
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if len(ports) == 0 {
|
||||
if out.String() == "No Instance(s) Available." {
|
||||
return "", errors.New("no serial ports available")
|
||||
} else if len(ports) > 1 {
|
||||
return "", errors.New("multiple serial ports available - use -port flag")
|
||||
}
|
||||
|
||||
return ports[0], nil
|
||||
for _, line := range strings.Split(out.String(), "\n") {
|
||||
words := strings.Fields(line)
|
||||
if len(words) == 1 {
|
||||
if strings.Contains(words[0], "COM") {
|
||||
return words[0], nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return "", errors.New("unable to locate a serial port")
|
||||
default:
|
||||
return "", errors.New("unable to search for a default USB device to be flashed on this OS")
|
||||
}
|
||||
@@ -704,7 +643,7 @@ func getDefaultPort() (port string, err error) {
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintln(os.Stderr, "TinyGo is a Go compiler for small places.")
|
||||
fmt.Fprintln(os.Stderr, "version:", goenv.Version)
|
||||
fmt.Fprintln(os.Stderr, "version:", version)
|
||||
fmt.Fprintf(os.Stderr, "usage: %s command [-printir] [-target=<target>] -o <output> <input>\n", os.Args[0])
|
||||
fmt.Fprintln(os.Stderr, "\ncommands:")
|
||||
fmt.Fprintln(os.Stderr, " build: compile packages and dependencies")
|
||||
@@ -713,27 +652,12 @@ func usage() {
|
||||
fmt.Fprintln(os.Stderr, " flash: compile and flash to the device")
|
||||
fmt.Fprintln(os.Stderr, " gdb: run/flash and immediately enter GDB")
|
||||
fmt.Fprintln(os.Stderr, " env: list environment variables used during build")
|
||||
fmt.Fprintln(os.Stderr, " list: run go list using the TinyGo root")
|
||||
fmt.Fprintln(os.Stderr, " clean: empty cache directory ("+goenv.Get("GOCACHE")+")")
|
||||
fmt.Fprintln(os.Stderr, " help: print this help text")
|
||||
fmt.Fprintln(os.Stderr, "\nflags:")
|
||||
flag.PrintDefaults()
|
||||
}
|
||||
|
||||
// try to make the path relative to the current working directory. If any error
|
||||
// occurs, this error is ignored and the absolute path is returned instead.
|
||||
func tryToMakePathRelative(dir string) string {
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return dir
|
||||
}
|
||||
relpath, err := filepath.Rel(wd, dir)
|
||||
if err != nil {
|
||||
return dir
|
||||
}
|
||||
return relpath
|
||||
}
|
||||
|
||||
// printCompilerError prints compiler errors using the provided logger function
|
||||
// (similar to fmt.Println).
|
||||
//
|
||||
@@ -741,24 +665,8 @@ func tryToMakePathRelative(dir string) string {
|
||||
// to limitations in the LLVM bindings.
|
||||
func printCompilerError(logln func(...interface{}), err error) {
|
||||
switch err := err.(type) {
|
||||
case types.Error:
|
||||
printCompilerError(logln, scanner.Error{
|
||||
Pos: err.Fset.Position(err.Pos),
|
||||
Msg: err.Msg,
|
||||
})
|
||||
case scanner.Error:
|
||||
if !strings.HasPrefix(err.Pos.Filename, filepath.Join(goenv.Get("GOROOT"), "src")) && !strings.HasPrefix(err.Pos.Filename, filepath.Join(goenv.Get("TINYGOROOT"), "src")) {
|
||||
// This file is not from the standard library (either the GOROOT or
|
||||
// the TINYGOROOT). Make the path relative, for easier reading.
|
||||
// Ignore any errors in the process (falling back to the absolute
|
||||
// path).
|
||||
err.Pos.Filename = tryToMakePathRelative(err.Pos.Filename)
|
||||
}
|
||||
case types.Error, scanner.Error:
|
||||
logln(err)
|
||||
case scanner.ErrorList:
|
||||
for _, scannerErr := range err {
|
||||
printCompilerError(logln, *scannerErr)
|
||||
}
|
||||
case *interp.Error:
|
||||
logln("#", err.ImportPath)
|
||||
logln(err.Error())
|
||||
@@ -777,17 +685,11 @@ func printCompilerError(logln func(...interface{}), err error) {
|
||||
case loader.Errors:
|
||||
logln("#", err.Pkg.ImportPath)
|
||||
for _, err := range err.Errs {
|
||||
printCompilerError(logln, err)
|
||||
}
|
||||
case loader.Error:
|
||||
logln(err.Err.Error())
|
||||
logln("package", err.ImportStack[0])
|
||||
for _, pkgPath := range err.ImportStack[1:] {
|
||||
logln("\timports", pkgPath)
|
||||
logln(err)
|
||||
}
|
||||
case *builder.MultiError:
|
||||
for _, err := range err.Errs {
|
||||
printCompilerError(logln, err)
|
||||
logln(err)
|
||||
}
|
||||
default:
|
||||
logln("error:", err)
|
||||
@@ -804,46 +706,32 @@ func handleCompilerError(err error) {
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Fprintln(os.Stderr, "No command-line arguments supplied.")
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
command := os.Args[1]
|
||||
|
||||
outpath := flag.String("o", "", "output filename")
|
||||
opt := flag.String("opt", "z", "optimization level: 0, 1, 2, s, z")
|
||||
gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, conservative)")
|
||||
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
|
||||
scheduler := flag.String("scheduler", "", "which scheduler to use (none, coroutines, tasks)")
|
||||
scheduler := flag.String("scheduler", "", "which scheduler to use (coroutines, tasks)")
|
||||
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")
|
||||
tags := flag.String("tags", "", "a space-separated list of extra build tags")
|
||||
target := flag.String("target", "", "LLVM target | .json file with TargetSpec")
|
||||
printSize := flag.String("size", "", "print sizes (none, short, full)")
|
||||
printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines")
|
||||
nodebug := flag.Bool("no-debug", false, "disable DWARF debug symbol generation")
|
||||
ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug")
|
||||
port := flag.String("port", "", "flash port")
|
||||
programmer := flag.String("programmer", "", "which hardware programmer to use")
|
||||
cFlags := flag.String("cflags", "", "additional cflags for compiler")
|
||||
ldFlags := flag.String("ldflags", "", "additional ldflags for linker")
|
||||
wasmAbi := flag.String("wasm-abi", "", "WebAssembly ABI conventions: js (no i64 params) or generic")
|
||||
wasmAbi := flag.String("wasm-abi", "js", "WebAssembly ABI conventions: js (no i64 params) or generic")
|
||||
heapSize := flag.String("heap-size", "1M", "default heap size in bytes (only supported by WebAssembly)")
|
||||
|
||||
var flagJSON, flagDeps *bool
|
||||
if command == "help" || command == "list" {
|
||||
flagJSON = flag.Bool("json", false, "print data in JSON format")
|
||||
flagDeps = flag.Bool("deps", false, "")
|
||||
}
|
||||
var outpath string
|
||||
if command == "help" || command == "build" || command == "build-library" || command == "test" {
|
||||
flag.StringVar(&outpath, "o", "", "output filename")
|
||||
}
|
||||
var testCompileOnlyFlag *bool
|
||||
if command == "help" || command == "test" {
|
||||
testCompileOnlyFlag = flag.Bool("c", false, "compile the test binary but do not run it")
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Fprintln(os.Stderr, "No command-line arguments supplied.")
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
command := os.Args[1]
|
||||
|
||||
// Early command processing, before commands are interpreted by the Go flag
|
||||
// library.
|
||||
@@ -869,7 +757,6 @@ func main() {
|
||||
VerifyIR: *verifyIR,
|
||||
Debug: !*nodebug,
|
||||
PrintSizes: *printSize,
|
||||
PrintStacks: *printStacks,
|
||||
Tags: *tags,
|
||||
WasmAbi: *wasmAbi,
|
||||
Programmer: *programmer,
|
||||
@@ -883,6 +770,12 @@ func main() {
|
||||
options.LDFlags = strings.Split(*ldFlags, " ")
|
||||
}
|
||||
|
||||
if *panicStrategy != "print" && *panicStrategy != "trap" {
|
||||
fmt.Fprintln(os.Stderr, "Panic strategy must be either print or trap.")
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var err error
|
||||
if options.HeapSize, err = parseSize(*heapSize); err != nil {
|
||||
fmt.Fprintln(os.Stderr, "Could not read heap size:", *heapSize)
|
||||
@@ -892,37 +785,29 @@ func main() {
|
||||
|
||||
os.Setenv("CC", "clang -target="+*target)
|
||||
|
||||
err = options.Verify()
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err.Error())
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
switch command {
|
||||
case "build":
|
||||
if outpath == "" {
|
||||
if *outpath == "" {
|
||||
fmt.Fprintln(os.Stderr, "No output filename supplied (-o).")
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
pkgName := "."
|
||||
if flag.NArg() == 1 {
|
||||
pkgName = filepath.ToSlash(flag.Arg(0))
|
||||
pkgName = flag.Arg(0)
|
||||
} else if flag.NArg() > 1 {
|
||||
fmt.Fprintln(os.Stderr, "build only accepts a single positional argument: package name, but multiple were specified")
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
if options.Target == "" && filepath.Ext(outpath) == ".wasm" {
|
||||
if options.Target == "" && filepath.Ext(*outpath) == ".wasm" {
|
||||
options.Target = "wasm"
|
||||
}
|
||||
|
||||
err := Build(pkgName, outpath, options)
|
||||
err := Build(pkgName, *outpath, options)
|
||||
handleCompilerError(err)
|
||||
case "build-library":
|
||||
// Note: this command is only meant to be used while making a release!
|
||||
if outpath == "" {
|
||||
if *outpath == "" {
|
||||
fmt.Fprintln(os.Stderr, "No output filename supplied (-o).")
|
||||
usage()
|
||||
os.Exit(1)
|
||||
@@ -947,11 +832,15 @@ func main() {
|
||||
}
|
||||
path, err := lib.Load(*target)
|
||||
handleCompilerError(err)
|
||||
copyFile(path, outpath)
|
||||
copyFile(path, *outpath)
|
||||
case "flash", "gdb":
|
||||
pkgName := filepath.ToSlash(flag.Arg(0))
|
||||
if *outpath != "" {
|
||||
fmt.Fprintln(os.Stderr, "Output cannot be specified with the flash command.")
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
if command == "flash" {
|
||||
err := Flash(pkgName, *port, options)
|
||||
err := Flash(flag.Arg(0), *port, options)
|
||||
handleCompilerError(err)
|
||||
} else {
|
||||
if !options.Debug {
|
||||
@@ -959,7 +848,7 @@ func main() {
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
err := FlashGDB(pkgName, *ocdOutput, options)
|
||||
err := FlashGDB(flag.Arg(0), *ocdOutput, options)
|
||||
handleCompilerError(err)
|
||||
}
|
||||
case "run":
|
||||
@@ -968,49 +857,19 @@ func main() {
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
pkgName := filepath.ToSlash(flag.Arg(0))
|
||||
err := Run(pkgName, options)
|
||||
err := Run(flag.Arg(0), options)
|
||||
handleCompilerError(err)
|
||||
case "test":
|
||||
pkgName := "."
|
||||
if flag.NArg() == 1 {
|
||||
pkgName = filepath.ToSlash(flag.Arg(0))
|
||||
pkgName = flag.Arg(0)
|
||||
} else if flag.NArg() > 1 {
|
||||
fmt.Fprintln(os.Stderr, "test only accepts a single positional argument: package name, but multiple were specified")
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
err := Test(pkgName, options, *testCompileOnlyFlag, outpath)
|
||||
err := Test(pkgName, options)
|
||||
handleCompilerError(err)
|
||||
case "targets":
|
||||
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
|
||||
entries, err := ioutil.ReadDir(dir)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "could not list targets:", err)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if !entry.Mode().IsRegular() || !strings.HasSuffix(entry.Name(), ".json") {
|
||||
// Only inspect JSON files.
|
||||
continue
|
||||
}
|
||||
path := filepath.Join(dir, entry.Name())
|
||||
spec, err := compileopts.LoadTarget(path)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "could not list target:", err)
|
||||
os.Exit(1)
|
||||
return
|
||||
}
|
||||
if spec.FlashMethod == "" && spec.FlashCommand == "" && spec.Emulator == nil {
|
||||
// This doesn't look like a regular target file, but rather like
|
||||
// a parent target (such as targets/cortex-m.json).
|
||||
continue
|
||||
}
|
||||
name := entry.Name()
|
||||
name = name[:len(name)-5]
|
||||
fmt.Println(name)
|
||||
}
|
||||
case "info":
|
||||
if flag.NArg() == 1 {
|
||||
options.Target = flag.Arg(0)
|
||||
@@ -1030,50 +889,12 @@ func main() {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cachedGOROOT, err := loader.GetCachedGoroot(config)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("LLVM triple: %s\n", config.Triple())
|
||||
fmt.Printf("GOOS: %s\n", config.GOOS())
|
||||
fmt.Printf("GOARCH: %s\n", config.GOARCH())
|
||||
fmt.Printf("build tags: %s\n", strings.Join(config.BuildTags(), " "))
|
||||
fmt.Printf("garbage collector: %s\n", config.GC())
|
||||
fmt.Printf("scheduler: %s\n", config.Scheduler())
|
||||
fmt.Printf("cached GOROOT: %s\n", cachedGOROOT)
|
||||
case "list":
|
||||
config, err := builder.NewConfig(options)
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
usage()
|
||||
os.Exit(1)
|
||||
}
|
||||
var extraArgs []string
|
||||
if *flagJSON {
|
||||
extraArgs = append(extraArgs, "-json")
|
||||
}
|
||||
if *flagDeps {
|
||||
extraArgs = append(extraArgs, "-deps")
|
||||
}
|
||||
cmd, err := loader.List(config, extraArgs, flag.Args())
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "failed to run `go list`:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
if exitErr, ok := err.(*exec.ExitError); ok {
|
||||
if status, ok := exitErr.Sys().(syscall.WaitStatus); ok {
|
||||
os.Exit(status.ExitStatus())
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Fprintln(os.Stderr, "failed to run `go list`:", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
case "clean":
|
||||
// remove cache directory
|
||||
err := os.RemoveAll(goenv.Get("GOCACHE"))
|
||||
@@ -1085,13 +906,9 @@ func main() {
|
||||
usage()
|
||||
case "version":
|
||||
goversion := "<unknown>"
|
||||
if s, err := goenv.GorootVersionString(goenv.Get("GOROOT")); err == nil {
|
||||
if s, err := builder.GorootVersionString(goenv.Get("GOROOT")); err == nil {
|
||||
goversion = s
|
||||
}
|
||||
version := goenv.Version
|
||||
if strings.HasSuffix(goenv.Version, "-dev") && gitSha1 != "" {
|
||||
version += "-" + gitSha1
|
||||
}
|
||||
fmt.Printf("tinygo version %s %s/%s (using go version %s and LLVM version %s)\n", version, runtime.GOOS, runtime.GOARCH, goversion, llvm.Version)
|
||||
case "env":
|
||||
if flag.NArg() == 0 {
|
||||
|
||||
+7
-26
@@ -6,7 +6,6 @@ package main
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
@@ -26,8 +25,6 @@ import (
|
||||
|
||||
const TESTDATA = "testdata"
|
||||
|
||||
var testTarget = flag.String("target", "", "override test target")
|
||||
|
||||
func TestCompiler(t *testing.T) {
|
||||
matches, err := filepath.Glob(filepath.Join(TESTDATA, "*.go"))
|
||||
if err != nil {
|
||||
@@ -47,14 +44,6 @@ func TestCompiler(t *testing.T) {
|
||||
|
||||
sort.Strings(matches)
|
||||
|
||||
if *testTarget != "" {
|
||||
// This makes it possible to run one specific test (instead of all),
|
||||
// which is especially useful to quickly check whether some changes
|
||||
// affect a particular target architecture.
|
||||
runPlatTests(*testTarget, matches, t)
|
||||
return
|
||||
}
|
||||
|
||||
if runtime.GOOS != "windows" {
|
||||
t.Run("Host", func(t *testing.T) {
|
||||
runPlatTests("", matches, t)
|
||||
@@ -78,16 +67,13 @@ func TestCompiler(t *testing.T) {
|
||||
}
|
||||
|
||||
if runtime.GOOS == "linux" {
|
||||
t.Run("X86Linux", func(t *testing.T) {
|
||||
runPlatTests("i386--linux-gnu", matches, t)
|
||||
})
|
||||
t.Run("ARMLinux", func(t *testing.T) {
|
||||
runPlatTests("arm--linux-gnueabihf", matches, t)
|
||||
})
|
||||
t.Run("ARM64Linux", func(t *testing.T) {
|
||||
runPlatTests("aarch64--linux-gnu", matches, t)
|
||||
})
|
||||
goVersion, err := goenv.GorootVersionString(goenv.Get("GOROOT"))
|
||||
goVersion, err := builder.GorootVersionString(goenv.Get("GOROOT"))
|
||||
if err != nil {
|
||||
t.Error("could not get Go version:", err)
|
||||
return
|
||||
@@ -101,10 +87,6 @@ func TestCompiler(t *testing.T) {
|
||||
runPlatTests("wasm", matches, t)
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("WASI", func(t *testing.T) {
|
||||
runPlatTests("wasi", matches, t)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,6 +98,7 @@ func runPlatTests(target string, matches []string, t *testing.T) {
|
||||
|
||||
t.Run(filepath.Base(path), func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
runTest(path, target, t)
|
||||
})
|
||||
}
|
||||
@@ -163,11 +146,10 @@ func runTest(path, target string, t *testing.T) {
|
||||
PrintIR: false,
|
||||
DumpSSA: false,
|
||||
VerifyIR: true,
|
||||
Debug: true,
|
||||
Debug: false,
|
||||
PrintSizes: "",
|
||||
WasmAbi: "",
|
||||
WasmAbi: "js",
|
||||
}
|
||||
|
||||
binary := filepath.Join(tmpdir, "test")
|
||||
err = runBuild("./"+path, binary, config)
|
||||
if err != nil {
|
||||
@@ -188,11 +170,10 @@ func runTest(path, target string, t *testing.T) {
|
||||
t.Fatal("failed to load target spec:", err)
|
||||
}
|
||||
if len(spec.Emulator) == 0 {
|
||||
cmd = exec.Command(binary)
|
||||
} else {
|
||||
args := append(spec.Emulator[1:], binary)
|
||||
cmd = exec.Command(spec.Emulator[0], args...)
|
||||
t.Fatal("no emulator available for target:", target)
|
||||
}
|
||||
args := append(spec.Emulator[1:], binary)
|
||||
cmd = exec.Command(spec.Emulator[0], args...)
|
||||
}
|
||||
stdout := &bytes.Buffer{}
|
||||
cmd.Stdout = stdout
|
||||
|
||||
+36
-6
@@ -76,8 +76,32 @@ const (
|
||||
SCS_BASE = 0xE000E000
|
||||
SYST_BASE = SCS_BASE + 0x0010
|
||||
NVIC_BASE = SCS_BASE + 0x0100
|
||||
SCB_BASE = SCS_BASE + 0x0D00
|
||||
)
|
||||
|
||||
const (
|
||||
SCB_AIRCR_VECTKEY_Pos = 16
|
||||
SCB_AIRCR_SYSRESETREQ_Pos = 2
|
||||
SCB_AIRCR_SYSRESETREQ_Msk = 1 << SCB_AIRCR_SYSRESETREQ_Pos
|
||||
)
|
||||
|
||||
// System Control Block (SCB)
|
||||
//
|
||||
// SCB_Type provides the definitions for the System Control Block Registers.
|
||||
type SCB_Type struct {
|
||||
CPUID volatile.Register32 // CPUID Base Register
|
||||
ICSR volatile.Register32 // Interrupt Control and State Register
|
||||
VTOR volatile.Register32 // Vector Table Offset Register
|
||||
AIRCR volatile.Register32 // Application Interrupt and Reset Control Register
|
||||
SCR volatile.Register32 // System Control Register
|
||||
CCR volatile.Register32 // Configuration Control Register
|
||||
_ volatile.Register32 // RESERVED1;
|
||||
SHP [2]volatile.Register32 // System Handlers Priority Registers. [0] is RESERVED
|
||||
SHCSR volatile.Register32 // System Handler Control and State Register
|
||||
}
|
||||
|
||||
var SCB = (*SCB_Type)(unsafe.Pointer(uintptr(SCB_BASE)))
|
||||
|
||||
// Nested Vectored Interrupt Controller (NVIC).
|
||||
//
|
||||
// Source:
|
||||
@@ -150,11 +174,6 @@ func EnableIRQ(irq uint32) {
|
||||
NVIC.ISER[irq>>5].Set(1 << (irq & 0x1F))
|
||||
}
|
||||
|
||||
// Disable the given interrupt number.
|
||||
func DisableIRQ(irq uint32) {
|
||||
NVIC.ICER[irq>>5].Set(1 << (irq & 0x1F))
|
||||
}
|
||||
|
||||
// Set the priority of the given interrupt number.
|
||||
// Note that the priority is given as a 0-255 number, where some of the lower
|
||||
// bits are not implemented by the hardware. For example, to set a low interrupt
|
||||
@@ -177,7 +196,7 @@ func SetPriority(irq uint32, priority uint32) {
|
||||
func DisableInterrupts() uintptr {
|
||||
return AsmFull(`
|
||||
mrs {}, PRIMASK
|
||||
cpsid i
|
||||
cpsid if
|
||||
`, nil)
|
||||
}
|
||||
|
||||
@@ -189,6 +208,17 @@ func EnableInterrupts(mask uintptr) {
|
||||
})
|
||||
}
|
||||
|
||||
// SystemReset performs a hard system reset.
|
||||
func SystemReset() {
|
||||
// SCB->AIRCR = ((0x5FA << SCB_AIRCR_VECTKEY_Pos) |
|
||||
// SCB_AIRCR_SYSRESETREQ_Msk);
|
||||
SCB.AIRCR.Set((0x5FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk)
|
||||
|
||||
for {
|
||||
Asm("wfi")
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the system timer to generate periodic tick events.
|
||||
// This will cause SysTick_Handler to fire once per tick.
|
||||
// The cyclecount parameter is a counter value which can range from 0 to
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
.syntax unified
|
||||
.cfi_sections .debug_frame
|
||||
|
||||
.section .text.HardFault_Handler
|
||||
.global HardFault_Handler
|
||||
.type HardFault_Handler, %function
|
||||
HardFault_Handler:
|
||||
.cfi_startproc
|
||||
// Put the old stack pointer in the first argument, for easy debugging. This
|
||||
// is especially useful on Cortex-M0, which supports far fewer debug
|
||||
// facilities.
|
||||
@@ -21,8 +19,6 @@ HardFault_Handler:
|
||||
|
||||
// Continue handling this error in Go.
|
||||
bl handleHardFault
|
||||
.cfi_endproc
|
||||
.size HardFault_Handler, .-HardFault_Handler
|
||||
|
||||
// This is a convenience function for semihosting support.
|
||||
// At some point, this should be replaced by inline assembly.
|
||||
@@ -30,8 +26,5 @@ HardFault_Handler:
|
||||
.global SemihostingCall
|
||||
.type SemihostingCall, %function
|
||||
SemihostingCall:
|
||||
.cfi_startproc
|
||||
bkpt 0xab
|
||||
bx lr
|
||||
.cfi_endproc
|
||||
.size SemihostingCall, .-SemihostingCall
|
||||
|
||||
@@ -1,431 +0,0 @@
|
||||
// Hand created file. DO NOT DELETE.
|
||||
// Cortex-M System Control Block-related definitions.
|
||||
|
||||
// +build cortexm
|
||||
|
||||
package arm
|
||||
|
||||
import (
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const SCB_BASE = SCS_BASE + 0x0D00
|
||||
|
||||
// System Control Block (SCB)
|
||||
//
|
||||
// SCB_Type provides the definitions for the System Control Block Registers.
|
||||
type SCB_Type struct {
|
||||
CPUID volatile.Register32 // 0xD00: CPUID Base Register
|
||||
ICSR volatile.Register32 // 0xD04: Interrupt Control and State Register
|
||||
VTOR volatile.Register32 // 0xD08: Vector Table Offset Register
|
||||
AIRCR volatile.Register32 // 0xD0C: Application Interrupt and Reset Control Register
|
||||
SCR volatile.Register32 // 0xD10: System Control Register
|
||||
CCR volatile.Register32 // 0xD14: Configuration and Control Register
|
||||
SHPR1 volatile.Register32 // 0xD18: System Handler Priority Register 1 (Cortex-M3/M33/M4/M7 only)
|
||||
SHPR2 volatile.Register32 // 0xD1C: System Handler Priority Register 2
|
||||
SHPR3 volatile.Register32 // 0xD20: System Handler Priority Register 3
|
||||
// the following are only applicable for Cortex-M3/M33/M4/M7
|
||||
SHCSR volatile.Register32 // 0xD24: System Handler Control and State Register
|
||||
CFSR volatile.Register32 // 0xD28: Configurable Fault Status Register
|
||||
HFSR volatile.Register32 // 0xD2C: HardFault Status Register
|
||||
DFSR volatile.Register32 // 0xD30: Debug Fault Status Register
|
||||
MMFAR volatile.Register32 // 0xD34: MemManage Fault Address Register
|
||||
BFAR volatile.Register32 // 0xD38: BusFault Address Register
|
||||
}
|
||||
|
||||
var SCB = (*SCB_Type)(unsafe.Pointer(uintptr(SCB_BASE)))
|
||||
|
||||
// SystemReset performs a hard system reset.
|
||||
func SystemReset() {
|
||||
SCB.AIRCR.Set((0x5FA << SCB_AIRCR_VECTKEY_Pos) | SCB_AIRCR_SYSRESETREQ_Msk)
|
||||
for {
|
||||
Asm("wfi")
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
// CPUID: CPUID Base Register
|
||||
SCB_CPUID_REVISION_Pos = 0x0 // Position of REVISION field.
|
||||
SCB_CPUID_REVISION_Msk = 0xf // Bit mask of REVISION field.
|
||||
SCB_CPUID_PARTNO_Pos = 0x4 // Position of PARTNO field.
|
||||
SCB_CPUID_PARTNO_Msk = 0xfff0 // Bit mask of PARTNO field.
|
||||
SCB_CPUID_ARCHITECTURE_Pos = 0x10 // Position of ARCHITECTURE field.
|
||||
SCB_CPUID_ARCHITECTURE_Msk = 0xf0000 // Bit mask of ARCHITECTURE field.
|
||||
SCB_CPUID_VARIANT_Pos = 0x14 // Position of VARIANT field.
|
||||
SCB_CPUID_VARIANT_Msk = 0xf00000 // Bit mask of VARIANT field.
|
||||
SCB_CPUID_IMPLEMENTER_Pos = 0x18 // Position of IMPLEMENTER field.
|
||||
SCB_CPUID_IMPLEMENTER_Msk = 0xff000000 // Bit mask of IMPLEMENTER field.
|
||||
|
||||
// ICSR: Interrupt Control and State Register
|
||||
SCB_ICSR_VECTACTIVE_Pos = 0x0 // Position of VECTACTIVE field.
|
||||
SCB_ICSR_VECTACTIVE_Msk = 0x1ff // Bit mask of VECTACTIVE field.
|
||||
SCB_ICSR_RETTOBASE_Pos = 0xb // Position of RETTOBASE field.
|
||||
SCB_ICSR_RETTOBASE_Msk = 0x800 // Bit mask of RETTOBASE field.
|
||||
SCB_ICSR_RETTOBASE = 0x800 // Bit RETTOBASE.
|
||||
SCB_ICSR_RETTOBASE_RETTOBASE_0 = 0x0 // there are preempted active exceptions to execute
|
||||
SCB_ICSR_RETTOBASE_RETTOBASE_1 = 0x1 // there are no active exceptions, or the currently-executing exception is the only active exception
|
||||
SCB_ICSR_VECTPENDING_Pos = 0xc // Position of VECTPENDING field.
|
||||
SCB_ICSR_VECTPENDING_Msk = 0x1ff000 // Bit mask of VECTPENDING field.
|
||||
SCB_ICSR_ISRPENDING_Pos = 0x16 // Position of ISRPENDING field.
|
||||
SCB_ICSR_ISRPENDING_Msk = 0x400000 // Bit mask of ISRPENDING field.
|
||||
SCB_ICSR_ISRPENDING = 0x400000 // Bit ISRPENDING.
|
||||
SCB_ICSR_ISRPENDING_ISRPENDING_0 = 0x0 // No external interrupt pending.
|
||||
SCB_ICSR_ISRPENDING_ISRPENDING_1 = 0x1 // External interrupt pending.
|
||||
SCB_ICSR_PENDSTCLR_Pos = 0x19 // Position of PENDSTCLR field.
|
||||
SCB_ICSR_PENDSTCLR_Msk = 0x2000000 // Bit mask of PENDSTCLR field.
|
||||
SCB_ICSR_PENDSTCLR = 0x2000000 // Bit PENDSTCLR.
|
||||
SCB_ICSR_PENDSTCLR_PENDSTCLR_0 = 0x0 // no effect
|
||||
SCB_ICSR_PENDSTCLR_PENDSTCLR_1 = 0x1 // removes the pending state from the SysTick exception
|
||||
SCB_ICSR_PENDSTSET_Pos = 0x1a // Position of PENDSTSET field.
|
||||
SCB_ICSR_PENDSTSET_Msk = 0x4000000 // Bit mask of PENDSTSET field.
|
||||
SCB_ICSR_PENDSTSET = 0x4000000 // Bit PENDSTSET.
|
||||
SCB_ICSR_PENDSTSET_PENDSTSET_0 = 0x0 // write: no effect; read: SysTick exception is not pending
|
||||
SCB_ICSR_PENDSTSET_PENDSTSET_1 = 0x1 // write: changes SysTick exception state to pending; read: SysTick exception is pending
|
||||
SCB_ICSR_PENDSVCLR_Pos = 0x1b // Position of PENDSVCLR field.
|
||||
SCB_ICSR_PENDSVCLR_Msk = 0x8000000 // Bit mask of PENDSVCLR field.
|
||||
SCB_ICSR_PENDSVCLR = 0x8000000 // Bit PENDSVCLR.
|
||||
SCB_ICSR_PENDSVCLR_PENDSVCLR_0 = 0x0 // no effect
|
||||
SCB_ICSR_PENDSVCLR_PENDSVCLR_1 = 0x1 // removes the pending state from the PendSV exception
|
||||
SCB_ICSR_PENDSVSET_Pos = 0x1c // Position of PENDSVSET field.
|
||||
SCB_ICSR_PENDSVSET_Msk = 0x10000000 // Bit mask of PENDSVSET field.
|
||||
SCB_ICSR_PENDSVSET = 0x10000000 // Bit PENDSVSET.
|
||||
SCB_ICSR_PENDSVSET_PENDSVSET_0 = 0x0 // write: no effect; read: PendSV exception is not pending
|
||||
SCB_ICSR_PENDSVSET_PENDSVSET_1 = 0x1 // write: changes PendSV exception state to pending; read: PendSV exception is pending
|
||||
SCB_ICSR_NMIPENDSET_Pos = 0x1f // Position of NMIPENDSET field.
|
||||
SCB_ICSR_NMIPENDSET_Msk = 0x80000000 // Bit mask of NMIPENDSET field.
|
||||
SCB_ICSR_NMIPENDSET = 0x80000000 // Bit NMIPENDSET.
|
||||
SCB_ICSR_NMIPENDSET_NMIPENDSET_0 = 0x0 // write: no effect; read: NMI exception is not pending
|
||||
SCB_ICSR_NMIPENDSET_NMIPENDSET_1 = 0x1 // write: changes NMI exception state to pending; read: NMI exception is pending
|
||||
|
||||
// VTOR: Vector Table Offset Register
|
||||
SCB_VTOR_TBLOFF_Pos = 0x7 // Position of TBLOFF field.
|
||||
SCB_VTOR_TBLOFF_Msk = 0xffffff80 // Bit mask of TBLOFF field.
|
||||
|
||||
// AIRCR: Application Interrupt and Reset Control Register
|
||||
SCB_AIRCR_VECTRESET_Pos = 0x0 // Position of VECTRESET field.
|
||||
SCB_AIRCR_VECTRESET_Msk = 0x1 // Bit mask of VECTRESET field.
|
||||
SCB_AIRCR_VECTRESET = 0x1 // Bit VECTRESET.
|
||||
SCB_AIRCR_VECTRESET_VECTRESET_0 = 0x0 // No change
|
||||
SCB_AIRCR_VECTRESET_VECTRESET_1 = 0x1 // Causes a local system reset
|
||||
SCB_AIRCR_VECTCLRACTIVE_Pos = 0x1 // Position of VECTCLRACTIVE field.
|
||||
SCB_AIRCR_VECTCLRACTIVE_Msk = 0x2 // Bit mask of VECTCLRACTIVE field.
|
||||
SCB_AIRCR_VECTCLRACTIVE = 0x2 // Bit VECTCLRACTIVE.
|
||||
SCB_AIRCR_VECTCLRACTIVE_VECTCLRACTIVE_0 = 0x0 // No change
|
||||
SCB_AIRCR_VECTCLRACTIVE_VECTCLRACTIVE_1 = 0x1 // Clears all active state information for fixed and configurable exceptions
|
||||
SCB_AIRCR_SYSRESETREQ_Pos = 0x2 // Position of SYSRESETREQ field.
|
||||
SCB_AIRCR_SYSRESETREQ_Msk = 0x4 // Bit mask of SYSRESETREQ field.
|
||||
SCB_AIRCR_SYSRESETREQ = 0x4 // Bit SYSRESETREQ.
|
||||
SCB_AIRCR_SYSRESETREQ_SYSRESETREQ_0 = 0x0 // no system reset request
|
||||
SCB_AIRCR_SYSRESETREQ_SYSRESETREQ_1 = 0x1 // asserts a signal to the outer system that requests a reset
|
||||
SCB_AIRCR_PRIGROUP_Pos = 0x8 // Position of PRIGROUP field.
|
||||
SCB_AIRCR_PRIGROUP_Msk = 0x700 // Bit mask of PRIGROUP field.
|
||||
SCB_AIRCR_ENDIANNESS_Pos = 0xf // Position of ENDIANNESS field.
|
||||
SCB_AIRCR_ENDIANNESS_Msk = 0x8000 // Bit mask of ENDIANNESS field.
|
||||
SCB_AIRCR_ENDIANNESS = 0x8000 // Bit ENDIANNESS.
|
||||
SCB_AIRCR_ENDIANNESS_ENDIANNESS_0 = 0x0 // Little-endian
|
||||
SCB_AIRCR_ENDIANNESS_ENDIANNESS_1 = 0x1 // Big-endian
|
||||
SCB_AIRCR_VECTKEY_Pos = 0x10 // Position of VECTKEY field.
|
||||
SCB_AIRCR_VECTKEY_Msk = 0xffff0000 // Bit mask of VECTKEY field.
|
||||
|
||||
// SCR: System Control Register
|
||||
SCB_SCR_SLEEPONEXIT_Pos = 0x1 // Position of SLEEPONEXIT field.
|
||||
SCB_SCR_SLEEPONEXIT_Msk = 0x2 // Bit mask of SLEEPONEXIT field.
|
||||
SCB_SCR_SLEEPONEXIT = 0x2 // Bit SLEEPONEXIT.
|
||||
SCB_SCR_SLEEPONEXIT_SLEEPONEXIT_0 = 0x0 // o not sleep when returning to Thread mode
|
||||
SCB_SCR_SLEEPONEXIT_SLEEPONEXIT_1 = 0x1 // enter sleep, or deep sleep, on return from an ISR
|
||||
SCB_SCR_SLEEPDEEP_Pos = 0x2 // Position of SLEEPDEEP field.
|
||||
SCB_SCR_SLEEPDEEP_Msk = 0x4 // Bit mask of SLEEPDEEP field.
|
||||
SCB_SCR_SLEEPDEEP = 0x4 // Bit SLEEPDEEP.
|
||||
SCB_SCR_SLEEPDEEP_SLEEPDEEP_0 = 0x0 // sleep
|
||||
SCB_SCR_SLEEPDEEP_SLEEPDEEP_1 = 0x1 // deep sleep
|
||||
SCB_SCR_SEVONPEND_Pos = 0x4 // Position of SEVONPEND field.
|
||||
SCB_SCR_SEVONPEND_Msk = 0x10 // Bit mask of SEVONPEND field.
|
||||
SCB_SCR_SEVONPEND = 0x10 // Bit SEVONPEND.
|
||||
SCB_SCR_SEVONPEND_SEVONPEND_0 = 0x0 // only enabled interrupts or events can wakeup the processor, disabled interrupts are excluded
|
||||
SCB_SCR_SEVONPEND_SEVONPEND_1 = 0x1 // enabled events and all interrupts, including disabled interrupts, can wakeup the processor
|
||||
|
||||
// CCR: Configuration and Control Register
|
||||
SCB_CCR_NONBASETHRDENA_Pos = 0x0 // Position of NONBASETHRDENA field.
|
||||
SCB_CCR_NONBASETHRDENA_Msk = 0x1 // Bit mask of NONBASETHRDENA field.
|
||||
SCB_CCR_NONBASETHRDENA = 0x1 // Bit NONBASETHRDENA.
|
||||
SCB_CCR_NONBASETHRDENA_NONBASETHRDENA_0 = 0x0 // processor can enter Thread mode only when no exception is active
|
||||
SCB_CCR_NONBASETHRDENA_NONBASETHRDENA_1 = 0x1 // processor can enter Thread mode from any level under the control of an EXC_RETURN value
|
||||
SCB_CCR_USERSETMPEND_Pos = 0x1 // Position of USERSETMPEND field.
|
||||
SCB_CCR_USERSETMPEND_Msk = 0x2 // Bit mask of USERSETMPEND field.
|
||||
SCB_CCR_USERSETMPEND = 0x2 // Bit USERSETMPEND.
|
||||
SCB_CCR_USERSETMPEND_USERSETMPEND_0 = 0x0 // disable
|
||||
SCB_CCR_USERSETMPEND_USERSETMPEND_1 = 0x1 // enable
|
||||
SCB_CCR_UNALIGN_TRP_Pos = 0x3 // Position of UNALIGN_TRP field.
|
||||
SCB_CCR_UNALIGN_TRP_Msk = 0x8 // Bit mask of UNALIGN_TRP field.
|
||||
SCB_CCR_UNALIGN_TRP = 0x8 // Bit UNALIGN_TRP.
|
||||
SCB_CCR_UNALIGN_TRP_UNALIGN_TRP_0 = 0x0 // do not trap unaligned halfword and word accesses
|
||||
SCB_CCR_UNALIGN_TRP_UNALIGN_TRP_1 = 0x1 // trap unaligned halfword and word accesses
|
||||
SCB_CCR_DIV_0_TRP_Pos = 0x4 // Position of DIV_0_TRP field.
|
||||
SCB_CCR_DIV_0_TRP_Msk = 0x10 // Bit mask of DIV_0_TRP field.
|
||||
SCB_CCR_DIV_0_TRP = 0x10 // Bit DIV_0_TRP.
|
||||
SCB_CCR_DIV_0_TRP_DIV_0_TRP_0 = 0x0 // do not trap divide by 0
|
||||
SCB_CCR_DIV_0_TRP_DIV_0_TRP_1 = 0x1 // trap divide by 0
|
||||
SCB_CCR_BFHFNMIGN_Pos = 0x8 // Position of BFHFNMIGN field.
|
||||
SCB_CCR_BFHFNMIGN_Msk = 0x100 // Bit mask of BFHFNMIGN field.
|
||||
SCB_CCR_BFHFNMIGN = 0x100 // Bit BFHFNMIGN.
|
||||
SCB_CCR_BFHFNMIGN_BFHFNMIGN_0 = 0x0 // data bus faults caused by load and store instructions cause a lock-up
|
||||
SCB_CCR_BFHFNMIGN_BFHFNMIGN_1 = 0x1 // handlers running at priority -1 and -2 ignore data bus faults caused by load and store instructions
|
||||
SCB_CCR_STKALIGN_Pos = 0x9 // Position of STKALIGN field.
|
||||
SCB_CCR_STKALIGN_Msk = 0x200 // Bit mask of STKALIGN field.
|
||||
SCB_CCR_STKALIGN = 0x200 // Bit STKALIGN.
|
||||
SCB_CCR_STKALIGN_STKALIGN_0 = 0x0 // 4-byte aligned
|
||||
SCB_CCR_STKALIGN_STKALIGN_1 = 0x1 // 8-byte aligned
|
||||
SCB_CCR_DC_Pos = 0x10 // Position of DC field.
|
||||
SCB_CCR_DC_Msk = 0x10000 // Bit mask of DC field.
|
||||
SCB_CCR_DC = 0x10000 // Bit DC.
|
||||
SCB_CCR_DC_DC_0 = 0x0 // L1 data cache disabled
|
||||
SCB_CCR_DC_DC_1 = 0x1 // L1 data cache enabled
|
||||
SCB_CCR_IC_Pos = 0x11 // Position of IC field.
|
||||
SCB_CCR_IC_Msk = 0x20000 // Bit mask of IC field.
|
||||
SCB_CCR_IC = 0x20000 // Bit IC.
|
||||
SCB_CCR_IC_IC_0 = 0x0 // L1 instruction cache disabled
|
||||
SCB_CCR_IC_IC_1 = 0x1 // L1 instruction cache enabled
|
||||
SCB_CCR_BP_Pos = 0x12 // Position of BP field.
|
||||
SCB_CCR_BP_Msk = 0x40000 // Bit mask of BP field.
|
||||
SCB_CCR_BP = 0x40000 // Bit BP.
|
||||
|
||||
// SHPR1: System Handler Priority Register 1
|
||||
SCB_SHPR1_PRI_4_Pos = 0x0 // Position of PRI_4 field.
|
||||
SCB_SHPR1_PRI_4_Msk = 0xff // Bit mask of PRI_4 field.
|
||||
SCB_SHPR1_PRI_5_Pos = 0x8 // Position of PRI_5 field.
|
||||
SCB_SHPR1_PRI_5_Msk = 0xff00 // Bit mask of PRI_5 field.
|
||||
SCB_SHPR1_PRI_6_Pos = 0x10 // Position of PRI_6 field.
|
||||
SCB_SHPR1_PRI_6_Msk = 0xff0000 // Bit mask of PRI_6 field.
|
||||
|
||||
// SHPR2: System Handler Priority Register 2
|
||||
SCB_SHPR2_PRI_11_Pos = 0x18 // Position of PRI_11 field.
|
||||
SCB_SHPR2_PRI_11_Msk = 0xff000000 // Bit mask of PRI_11 field.
|
||||
|
||||
// SHPR3: System Handler Priority Register 3
|
||||
SCB_SHPR3_PRI_14_Pos = 0x10 // Position of PRI_14 field.
|
||||
SCB_SHPR3_PRI_14_Msk = 0xff0000 // Bit mask of PRI_14 field.
|
||||
SCB_SHPR3_PRI_15_Pos = 0x18 // Position of PRI_15 field.
|
||||
SCB_SHPR3_PRI_15_Msk = 0xff000000 // Bit mask of PRI_15 field.
|
||||
|
||||
// SHCSR: System Handler Control and State Register
|
||||
SCB_SHCSR_MEMFAULTACT_Pos = 0x0 // Position of MEMFAULTACT field.
|
||||
SCB_SHCSR_MEMFAULTACT_Msk = 0x1 // Bit mask of MEMFAULTACT field.
|
||||
SCB_SHCSR_MEMFAULTACT = 0x1 // Bit MEMFAULTACT.
|
||||
SCB_SHCSR_MEMFAULTACT_MEMFAULTACT_0 = 0x0 // exception is not active
|
||||
SCB_SHCSR_MEMFAULTACT_MEMFAULTACT_1 = 0x1 // exception is active
|
||||
SCB_SHCSR_BUSFAULTACT_Pos = 0x1 // Position of BUSFAULTACT field.
|
||||
SCB_SHCSR_BUSFAULTACT_Msk = 0x2 // Bit mask of BUSFAULTACT field.
|
||||
SCB_SHCSR_BUSFAULTACT = 0x2 // Bit BUSFAULTACT.
|
||||
SCB_SHCSR_BUSFAULTACT_BUSFAULTACT_0 = 0x0 // exception is not active
|
||||
SCB_SHCSR_BUSFAULTACT_BUSFAULTACT_1 = 0x1 // exception is active
|
||||
SCB_SHCSR_USGFAULTACT_Pos = 0x3 // Position of USGFAULTACT field.
|
||||
SCB_SHCSR_USGFAULTACT_Msk = 0x8 // Bit mask of USGFAULTACT field.
|
||||
SCB_SHCSR_USGFAULTACT = 0x8 // Bit USGFAULTACT.
|
||||
SCB_SHCSR_USGFAULTACT_USGFAULTACT_0 = 0x0 // exception is not active
|
||||
SCB_SHCSR_USGFAULTACT_USGFAULTACT_1 = 0x1 // exception is active
|
||||
SCB_SHCSR_SVCALLACT_Pos = 0x7 // Position of SVCALLACT field.
|
||||
SCB_SHCSR_SVCALLACT_Msk = 0x80 // Bit mask of SVCALLACT field.
|
||||
SCB_SHCSR_SVCALLACT = 0x80 // Bit SVCALLACT.
|
||||
SCB_SHCSR_SVCALLACT_SVCALLACT_0 = 0x0 // exception is not active
|
||||
SCB_SHCSR_SVCALLACT_SVCALLACT_1 = 0x1 // exception is active
|
||||
SCB_SHCSR_MONITORACT_Pos = 0x8 // Position of MONITORACT field.
|
||||
SCB_SHCSR_MONITORACT_Msk = 0x100 // Bit mask of MONITORACT field.
|
||||
SCB_SHCSR_MONITORACT = 0x100 // Bit MONITORACT.
|
||||
SCB_SHCSR_MONITORACT_MONITORACT_0 = 0x0 // exception is not active
|
||||
SCB_SHCSR_MONITORACT_MONITORACT_1 = 0x1 // exception is active
|
||||
SCB_SHCSR_PENDSVACT_Pos = 0xa // Position of PENDSVACT field.
|
||||
SCB_SHCSR_PENDSVACT_Msk = 0x400 // Bit mask of PENDSVACT field.
|
||||
SCB_SHCSR_PENDSVACT = 0x400 // Bit PENDSVACT.
|
||||
SCB_SHCSR_PENDSVACT_PENDSVACT_0 = 0x0 // exception is not active
|
||||
SCB_SHCSR_PENDSVACT_PENDSVACT_1 = 0x1 // exception is active
|
||||
SCB_SHCSR_SYSTICKACT_Pos = 0xb // Position of SYSTICKACT field.
|
||||
SCB_SHCSR_SYSTICKACT_Msk = 0x800 // Bit mask of SYSTICKACT field.
|
||||
SCB_SHCSR_SYSTICKACT = 0x800 // Bit SYSTICKACT.
|
||||
SCB_SHCSR_SYSTICKACT_SYSTICKACT_0 = 0x0 // exception is not active
|
||||
SCB_SHCSR_SYSTICKACT_SYSTICKACT_1 = 0x1 // exception is active
|
||||
SCB_SHCSR_USGFAULTPENDED_Pos = 0xc // Position of USGFAULTPENDED field.
|
||||
SCB_SHCSR_USGFAULTPENDED_Msk = 0x1000 // Bit mask of USGFAULTPENDED field.
|
||||
SCB_SHCSR_USGFAULTPENDED = 0x1000 // Bit USGFAULTPENDED.
|
||||
SCB_SHCSR_USGFAULTPENDED_USGFAULTPENDED_0 = 0x0 // exception is not pending
|
||||
SCB_SHCSR_USGFAULTPENDED_USGFAULTPENDED_1 = 0x1 // exception is pending
|
||||
SCB_SHCSR_MEMFAULTPENDED_Pos = 0xd // Position of MEMFAULTPENDED field.
|
||||
SCB_SHCSR_MEMFAULTPENDED_Msk = 0x2000 // Bit mask of MEMFAULTPENDED field.
|
||||
SCB_SHCSR_MEMFAULTPENDED = 0x2000 // Bit MEMFAULTPENDED.
|
||||
SCB_SHCSR_MEMFAULTPENDED_MEMFAULTPENDED_0 = 0x0 // exception is not pending
|
||||
SCB_SHCSR_MEMFAULTPENDED_MEMFAULTPENDED_1 = 0x1 // exception is pending
|
||||
SCB_SHCSR_BUSFAULTPENDED_Pos = 0xe // Position of BUSFAULTPENDED field.
|
||||
SCB_SHCSR_BUSFAULTPENDED_Msk = 0x4000 // Bit mask of BUSFAULTPENDED field.
|
||||
SCB_SHCSR_BUSFAULTPENDED = 0x4000 // Bit BUSFAULTPENDED.
|
||||
SCB_SHCSR_BUSFAULTPENDED_BUSFAULTPENDED_0 = 0x0 // exception is not pending
|
||||
SCB_SHCSR_BUSFAULTPENDED_BUSFAULTPENDED_1 = 0x1 // exception is pending
|
||||
SCB_SHCSR_SVCALLPENDED_Pos = 0xf // Position of SVCALLPENDED field.
|
||||
SCB_SHCSR_SVCALLPENDED_Msk = 0x8000 // Bit mask of SVCALLPENDED field.
|
||||
SCB_SHCSR_SVCALLPENDED = 0x8000 // Bit SVCALLPENDED.
|
||||
SCB_SHCSR_SVCALLPENDED_SVCALLPENDED_0 = 0x0 // exception is not pending
|
||||
SCB_SHCSR_SVCALLPENDED_SVCALLPENDED_1 = 0x1 // exception is pending
|
||||
SCB_SHCSR_MEMFAULTENA_Pos = 0x10 // Position of MEMFAULTENA field.
|
||||
SCB_SHCSR_MEMFAULTENA_Msk = 0x10000 // Bit mask of MEMFAULTENA field.
|
||||
SCB_SHCSR_MEMFAULTENA = 0x10000 // Bit MEMFAULTENA.
|
||||
SCB_SHCSR_MEMFAULTENA_MEMFAULTENA_0 = 0x0 // disable the exception
|
||||
SCB_SHCSR_MEMFAULTENA_MEMFAULTENA_1 = 0x1 // enable the exception
|
||||
SCB_SHCSR_BUSFAULTENA_Pos = 0x11 // Position of BUSFAULTENA field.
|
||||
SCB_SHCSR_BUSFAULTENA_Msk = 0x20000 // Bit mask of BUSFAULTENA field.
|
||||
SCB_SHCSR_BUSFAULTENA = 0x20000 // Bit BUSFAULTENA.
|
||||
SCB_SHCSR_BUSFAULTENA_BUSFAULTENA_0 = 0x0 // disable the exception
|
||||
SCB_SHCSR_BUSFAULTENA_BUSFAULTENA_1 = 0x1 // enable the exception
|
||||
SCB_SHCSR_USGFAULTENA_Pos = 0x12 // Position of USGFAULTENA field.
|
||||
SCB_SHCSR_USGFAULTENA_Msk = 0x40000 // Bit mask of USGFAULTENA field.
|
||||
SCB_SHCSR_USGFAULTENA = 0x40000 // Bit USGFAULTENA.
|
||||
SCB_SHCSR_USGFAULTENA_USGFAULTENA_0 = 0x0 // disable the exception
|
||||
SCB_SHCSR_USGFAULTENA_USGFAULTENA_1 = 0x1 // enable the exception
|
||||
|
||||
// CFSR: Configurable Fault Status Register
|
||||
SCB_CFSR_IACCVIOL_Pos = 0x0 // Position of IACCVIOL field.
|
||||
SCB_CFSR_IACCVIOL_Msk = 0x1 // Bit mask of IACCVIOL field.
|
||||
SCB_CFSR_IACCVIOL = 0x1 // Bit IACCVIOL.
|
||||
SCB_CFSR_IACCVIOL_IACCVIOL_0 = 0x0 // no instruction access violation fault
|
||||
SCB_CFSR_IACCVIOL_IACCVIOL_1 = 0x1 // the processor attempted an instruction fetch from a location that does not permit execution
|
||||
SCB_CFSR_DACCVIOL_Pos = 0x1 // Position of DACCVIOL field.
|
||||
SCB_CFSR_DACCVIOL_Msk = 0x2 // Bit mask of DACCVIOL field.
|
||||
SCB_CFSR_DACCVIOL = 0x2 // Bit DACCVIOL.
|
||||
SCB_CFSR_DACCVIOL_DACCVIOL_0 = 0x0 // no data access violation fault
|
||||
SCB_CFSR_DACCVIOL_DACCVIOL_1 = 0x1 // the processor attempted a load or store at a location that does not permit the operation
|
||||
SCB_CFSR_MUNSTKERR_Pos = 0x3 // Position of MUNSTKERR field.
|
||||
SCB_CFSR_MUNSTKERR_Msk = 0x8 // Bit mask of MUNSTKERR field.
|
||||
SCB_CFSR_MUNSTKERR = 0x8 // Bit MUNSTKERR.
|
||||
SCB_CFSR_MUNSTKERR_MUNSTKERR_0 = 0x0 // no unstacking fault
|
||||
SCB_CFSR_MUNSTKERR_MUNSTKERR_1 = 0x1 // unstack for an exception return has caused one or more access violations
|
||||
SCB_CFSR_MSTKERR_Pos = 0x4 // Position of MSTKERR field.
|
||||
SCB_CFSR_MSTKERR_Msk = 0x10 // Bit mask of MSTKERR field.
|
||||
SCB_CFSR_MSTKERR = 0x10 // Bit MSTKERR.
|
||||
SCB_CFSR_MSTKERR_MSTKERR_0 = 0x0 // no stacking fault
|
||||
SCB_CFSR_MSTKERR_MSTKERR_1 = 0x1 // stacking for an exception entry has caused one or more access violations
|
||||
SCB_CFSR_MLSPERR_Pos = 0x5 // Position of MLSPERR field.
|
||||
SCB_CFSR_MLSPERR_Msk = 0x20 // Bit mask of MLSPERR field.
|
||||
SCB_CFSR_MLSPERR = 0x20 // Bit MLSPERR.
|
||||
SCB_CFSR_MLSPERR_MLSPERR_0 = 0x0 // No MemManage fault occurred during floating-point lazy state preservation
|
||||
SCB_CFSR_MLSPERR_MLSPERR_1 = 0x1 // A MemManage fault occurred during floating-point lazy state preservation
|
||||
SCB_CFSR_MMARVALID_Pos = 0x7 // Position of MMARVALID field.
|
||||
SCB_CFSR_MMARVALID_Msk = 0x80 // Bit mask of MMARVALID field.
|
||||
SCB_CFSR_MMARVALID = 0x80 // Bit MMARVALID.
|
||||
SCB_CFSR_MMARVALID_MMARVALID_0 = 0x0 // value in MMAR is not a valid fault address
|
||||
SCB_CFSR_MMARVALID_MMARVALID_1 = 0x1 // MMAR holds a valid fault address
|
||||
SCB_CFSR_IBUSERR_Pos = 0x8 // Position of IBUSERR field.
|
||||
SCB_CFSR_IBUSERR_Msk = 0x100 // Bit mask of IBUSERR field.
|
||||
SCB_CFSR_IBUSERR = 0x100 // Bit IBUSERR.
|
||||
SCB_CFSR_IBUSERR_IBUSERR_0 = 0x0 // no instruction bus error
|
||||
SCB_CFSR_IBUSERR_IBUSERR_1 = 0x1 // instruction bus error
|
||||
SCB_CFSR_PRECISERR_Pos = 0x9 // Position of PRECISERR field.
|
||||
SCB_CFSR_PRECISERR_Msk = 0x200 // Bit mask of PRECISERR field.
|
||||
SCB_CFSR_PRECISERR = 0x200 // Bit PRECISERR.
|
||||
SCB_CFSR_PRECISERR_PRECISERR_0 = 0x0 // no precise data bus error
|
||||
SCB_CFSR_PRECISERR_PRECISERR_1 = 0x1 // a data bus error has occurred, and the PC value stacked for the exception return points to the instruction that caused the fault
|
||||
SCB_CFSR_IMPRECISERR_Pos = 0xa // Position of IMPRECISERR field.
|
||||
SCB_CFSR_IMPRECISERR_Msk = 0x400 // Bit mask of IMPRECISERR field.
|
||||
SCB_CFSR_IMPRECISERR = 0x400 // Bit IMPRECISERR.
|
||||
SCB_CFSR_IMPRECISERR_IMPRECISERR_0 = 0x0 // no imprecise data bus error
|
||||
SCB_CFSR_IMPRECISERR_IMPRECISERR_1 = 0x1 // a data bus error has occurred, but the return address in the stack frame is not related to the instruction that caused the error
|
||||
SCB_CFSR_UNSTKERR_Pos = 0xb // Position of UNSTKERR field.
|
||||
SCB_CFSR_UNSTKERR_Msk = 0x800 // Bit mask of UNSTKERR field.
|
||||
SCB_CFSR_UNSTKERR = 0x800 // Bit UNSTKERR.
|
||||
SCB_CFSR_UNSTKERR_UNSTKERR_0 = 0x0 // no unstacking fault
|
||||
SCB_CFSR_UNSTKERR_UNSTKERR_1 = 0x1 // unstack for an exception return has caused one or more BusFaults
|
||||
SCB_CFSR_STKERR_Pos = 0xc // Position of STKERR field.
|
||||
SCB_CFSR_STKERR_Msk = 0x1000 // Bit mask of STKERR field.
|
||||
SCB_CFSR_STKERR = 0x1000 // Bit STKERR.
|
||||
SCB_CFSR_STKERR_STKERR_0 = 0x0 // no stacking fault
|
||||
SCB_CFSR_STKERR_STKERR_1 = 0x1 // stacking for an exception entry has caused one or more BusFaults
|
||||
SCB_CFSR_LSPERR_Pos = 0xd // Position of LSPERR field.
|
||||
SCB_CFSR_LSPERR_Msk = 0x2000 // Bit mask of LSPERR field.
|
||||
SCB_CFSR_LSPERR = 0x2000 // Bit LSPERR.
|
||||
SCB_CFSR_LSPERR_LSPERR_0 = 0x0 // No bus fault occurred during floating-point lazy state preservation
|
||||
SCB_CFSR_LSPERR_LSPERR_1 = 0x1 // A bus fault occurred during floating-point lazy state preservation
|
||||
SCB_CFSR_BFARVALID_Pos = 0xf // Position of BFARVALID field.
|
||||
SCB_CFSR_BFARVALID_Msk = 0x8000 // Bit mask of BFARVALID field.
|
||||
SCB_CFSR_BFARVALID = 0x8000 // Bit BFARVALID.
|
||||
SCB_CFSR_BFARVALID_BFARVALID_0 = 0x0 // value in BFAR is not a valid fault address
|
||||
SCB_CFSR_BFARVALID_BFARVALID_1 = 0x1 // BFAR holds a valid fault address
|
||||
SCB_CFSR_UNDEFINSTR_Pos = 0x10 // Position of UNDEFINSTR field.
|
||||
SCB_CFSR_UNDEFINSTR_Msk = 0x10000 // Bit mask of UNDEFINSTR field.
|
||||
SCB_CFSR_UNDEFINSTR = 0x10000 // Bit UNDEFINSTR.
|
||||
SCB_CFSR_UNDEFINSTR_UNDEFINSTR_0 = 0x0 // no undefined instruction UsageFault
|
||||
SCB_CFSR_UNDEFINSTR_UNDEFINSTR_1 = 0x1 // the processor has attempted to execute an undefined instruction
|
||||
SCB_CFSR_INVSTATE_Pos = 0x11 // Position of INVSTATE field.
|
||||
SCB_CFSR_INVSTATE_Msk = 0x20000 // Bit mask of INVSTATE field.
|
||||
SCB_CFSR_INVSTATE = 0x20000 // Bit INVSTATE.
|
||||
SCB_CFSR_INVSTATE_INVSTATE_0 = 0x0 // no invalid state UsageFault
|
||||
SCB_CFSR_INVSTATE_INVSTATE_1 = 0x1 // the processor has attempted to execute an instruction that makes illegal use of the EPSR
|
||||
SCB_CFSR_INVPC_Pos = 0x12 // Position of INVPC field.
|
||||
SCB_CFSR_INVPC_Msk = 0x40000 // Bit mask of INVPC field.
|
||||
SCB_CFSR_INVPC = 0x40000 // Bit INVPC.
|
||||
SCB_CFSR_INVPC_INVPC_0 = 0x0 // no invalid PC load UsageFault
|
||||
SCB_CFSR_INVPC_INVPC_1 = 0x1 // the processor has attempted an illegal load of EXC_RETURN to the PC
|
||||
SCB_CFSR_NOCP_Pos = 0x13 // Position of NOCP field.
|
||||
SCB_CFSR_NOCP_Msk = 0x80000 // Bit mask of NOCP field.
|
||||
SCB_CFSR_NOCP = 0x80000 // Bit NOCP.
|
||||
SCB_CFSR_NOCP_NOCP_0 = 0x0 // no UsageFault caused by attempting to access a coprocessor
|
||||
SCB_CFSR_NOCP_NOCP_1 = 0x1 // the processor has attempted to access a coprocessor
|
||||
SCB_CFSR_UNALIGNED_Pos = 0x18 // Position of UNALIGNED field.
|
||||
SCB_CFSR_UNALIGNED_Msk = 0x1000000 // Bit mask of UNALIGNED field.
|
||||
SCB_CFSR_UNALIGNED = 0x1000000 // Bit UNALIGNED.
|
||||
SCB_CFSR_UNALIGNED_UNALIGNED_0 = 0x0 // no unaligned access fault, or unaligned access trapping not enabled
|
||||
SCB_CFSR_UNALIGNED_UNALIGNED_1 = 0x1 // the processor has made an unaligned memory access
|
||||
SCB_CFSR_DIVBYZERO_Pos = 0x19 // Position of DIVBYZERO field.
|
||||
SCB_CFSR_DIVBYZERO_Msk = 0x2000000 // Bit mask of DIVBYZERO field.
|
||||
SCB_CFSR_DIVBYZERO = 0x2000000 // Bit DIVBYZERO.
|
||||
SCB_CFSR_DIVBYZERO_DIVBYZERO_0 = 0x0 // no divide by zero fault, or divide by zero trapping not enabled
|
||||
SCB_CFSR_DIVBYZERO_DIVBYZERO_1 = 0x1 // the processor has executed an SDIV or UDIV instruction with a divisor of 0
|
||||
|
||||
// HFSR: HardFault Status register
|
||||
SCB_HFSR_VECTTBL_Pos = 0x1 // Position of VECTTBL field.
|
||||
SCB_HFSR_VECTTBL_Msk = 0x2 // Bit mask of VECTTBL field.
|
||||
SCB_HFSR_VECTTBL = 0x2 // Bit VECTTBL.
|
||||
SCB_HFSR_VECTTBL_VECTTBL_0 = 0x0 // no BusFault on vector table read
|
||||
SCB_HFSR_VECTTBL_VECTTBL_1 = 0x1 // BusFault on vector table read
|
||||
SCB_HFSR_FORCED_Pos = 0x1e // Position of FORCED field.
|
||||
SCB_HFSR_FORCED_Msk = 0x40000000 // Bit mask of FORCED field.
|
||||
SCB_HFSR_FORCED = 0x40000000 // Bit FORCED.
|
||||
SCB_HFSR_FORCED_FORCED_0 = 0x0 // no forced HardFault
|
||||
SCB_HFSR_FORCED_FORCED_1 = 0x1 // forced HardFault
|
||||
SCB_HFSR_DEBUGEVT_Pos = 0x1f // Position of DEBUGEVT field.
|
||||
SCB_HFSR_DEBUGEVT_Msk = 0x80000000 // Bit mask of DEBUGEVT field.
|
||||
SCB_HFSR_DEBUGEVT = 0x80000000 // Bit DEBUGEVT.
|
||||
SCB_HFSR_DEBUGEVT_DEBUGEVT_0 = 0x0 // No Debug event has occurred.
|
||||
SCB_HFSR_DEBUGEVT_DEBUGEVT_1 = 0x1 // Debug event has occurred. The Debug Fault Status Register has been updated.
|
||||
|
||||
// DFSR: Debug Fault Status Register
|
||||
SCB_DFSR_HALTED_Pos = 0x0 // Position of HALTED field.
|
||||
SCB_DFSR_HALTED_Msk = 0x1 // Bit mask of HALTED field.
|
||||
SCB_DFSR_HALTED = 0x1 // Bit HALTED.
|
||||
SCB_DFSR_HALTED_HALTED_0 = 0x0 // No active halt request debug event
|
||||
SCB_DFSR_HALTED_HALTED_1 = 0x1 // Halt request debug event active
|
||||
SCB_DFSR_BKPT_Pos = 0x1 // Position of BKPT field.
|
||||
SCB_DFSR_BKPT_Msk = 0x2 // Bit mask of BKPT field.
|
||||
SCB_DFSR_BKPT = 0x2 // Bit BKPT.
|
||||
SCB_DFSR_BKPT_BKPT_0 = 0x0 // No current breakpoint debug event
|
||||
SCB_DFSR_BKPT_BKPT_1 = 0x1 // At least one current breakpoint debug event
|
||||
SCB_DFSR_DWTTRAP_Pos = 0x2 // Position of DWTTRAP field.
|
||||
SCB_DFSR_DWTTRAP_Msk = 0x4 // Bit mask of DWTTRAP field.
|
||||
SCB_DFSR_DWTTRAP = 0x4 // Bit DWTTRAP.
|
||||
SCB_DFSR_DWTTRAP_DWTTRAP_0 = 0x0 // No current debug events generated by the DWT
|
||||
SCB_DFSR_DWTTRAP_DWTTRAP_1 = 0x1 // At least one current debug event generated by the DWT
|
||||
SCB_DFSR_VCATCH_Pos = 0x3 // Position of VCATCH field.
|
||||
SCB_DFSR_VCATCH_Msk = 0x8 // Bit mask of VCATCH field.
|
||||
SCB_DFSR_VCATCH = 0x8 // Bit VCATCH.
|
||||
SCB_DFSR_VCATCH_VCATCH_0 = 0x0 // No Vector catch triggered
|
||||
SCB_DFSR_VCATCH_VCATCH_1 = 0x1 // Vector catch triggered
|
||||
SCB_DFSR_EXTERNAL_Pos = 0x4 // Position of EXTERNAL field.
|
||||
SCB_DFSR_EXTERNAL_Msk = 0x10 // Bit mask of EXTERNAL field.
|
||||
SCB_DFSR_EXTERNAL = 0x10 // Bit EXTERNAL.
|
||||
SCB_DFSR_EXTERNAL_EXTERNAL_0 = 0x0 // No external debug request debug event
|
||||
SCB_DFSR_EXTERNAL_EXTERNAL_1 = 0x1 // External debug request debug event
|
||||
|
||||
// MMFAR: MemManage Fault Address Register
|
||||
SCB_MMFAR_ADDRESS_Pos = 0x0 // Position of ADDRESS field.
|
||||
SCB_MMFAR_ADDRESS_Msk = 0xffffffff // Bit mask of ADDRESS field.
|
||||
|
||||
// BFAR: BusFault Address Register
|
||||
SCB_BFAR_ADDRESS_Pos = 0x0 // Position of ADDRESS field.
|
||||
SCB_BFAR_ADDRESS_Msk = 0xffffffff // Bit mask of ADDRESS field.
|
||||
)
|
||||
@@ -1,36 +0,0 @@
|
||||
package arm64
|
||||
|
||||
// Run the given assembly code. The code will be marked as having side effects,
|
||||
// as it doesn't produce output and thus would normally be eliminated by the
|
||||
// optimizer.
|
||||
func Asm(asm string)
|
||||
|
||||
// Run the given inline assembly. The code will be marked as having side
|
||||
// effects, as it would otherwise be optimized away. The inline assembly string
|
||||
// recognizes template values in the form {name}, like so:
|
||||
//
|
||||
// arm.AsmFull(
|
||||
// "str {value}, {result}",
|
||||
// map[string]interface{}{
|
||||
// "value": 1
|
||||
// "result": &dest,
|
||||
// })
|
||||
//
|
||||
// You can use {} in the asm string (which expands to a register) to set the
|
||||
// return value.
|
||||
func AsmFull(asm string, regs map[string]interface{}) uintptr
|
||||
|
||||
// Run the following system call (SVCall) with 0 arguments.
|
||||
func SVCall0(num uintptr) uintptr
|
||||
|
||||
// Run the following system call (SVCall) with 1 argument.
|
||||
func SVCall1(num uintptr, a1 interface{}) uintptr
|
||||
|
||||
// Run the following system call (SVCall) with 2 arguments.
|
||||
func SVCall2(num uintptr, a1, a2 interface{}) uintptr
|
||||
|
||||
// Run the following system call (SVCall) with 3 arguments.
|
||||
func SVCall3(num uintptr, a1, a2, a3 interface{}) uintptr
|
||||
|
||||
// Run the following system call (SVCall) with 4 arguments.
|
||||
func SVCall4(num uintptr, a1, a2, a3, a4 interface{}) uintptr
|
||||
@@ -1,21 +0,0 @@
|
||||
package device
|
||||
|
||||
// Run the given assembly code. The code will be marked as having side effects,
|
||||
// as it doesn't produce output and thus would normally be eliminated by the
|
||||
// optimizer.
|
||||
func Asm(asm string)
|
||||
|
||||
// Run the given inline assembly. The code will be marked as having side
|
||||
// effects, as it would otherwise be optimized away. The inline assembly string
|
||||
// recognizes template values in the form {name}, like so:
|
||||
//
|
||||
// arm.AsmFull(
|
||||
// "str {value}, {result}",
|
||||
// map[string]interface{}{
|
||||
// "value": 1
|
||||
// "result": &dest,
|
||||
// })
|
||||
//
|
||||
// You can use {} in the asm string (which expands to a register) to set the
|
||||
// return value.
|
||||
func AsmFull(asm string, regs map[string]interface{}) uintptr
|
||||
@@ -1,52 +0,0 @@
|
||||
|
||||
// The following definitions were copied from:
|
||||
// esp-idf/components/xtensa/include/xtensa/corebits.h
|
||||
#define PS_WOE_MASK 0x00040000
|
||||
#define PS_OWB_MASK 0x00000F00
|
||||
#define PS_CALLINC_MASK 0x00030000
|
||||
#define PS_WOE PS_WOE_MASK
|
||||
|
||||
// Only calling it call_start_cpu0 for consistency with ESP-IDF.
|
||||
.section .text.call_start_cpu0
|
||||
1:
|
||||
.long _stack_top
|
||||
.global call_start_cpu0
|
||||
call_start_cpu0:
|
||||
// We need to set the stack pointer to a different value. This is somewhat
|
||||
// complicated in the Xtensa architecture. The code below is a modified
|
||||
// version of the following code:
|
||||
// https://github.com/espressif/esp-idf/blob/c77c4ccf/components/xtensa/include/xt_instr_macros.h#L47
|
||||
|
||||
// Disable WOE.
|
||||
rsr.ps a2
|
||||
movi a3, ~(PS_WOE_MASK)
|
||||
and a2, a2, a3
|
||||
wsr.ps a2
|
||||
rsync
|
||||
|
||||
// Set WINDOWBASE to 1 << WINDOWSTART.
|
||||
rsr.windowbase a2
|
||||
ssl a2
|
||||
movi a2, 1
|
||||
sll a2, a2
|
||||
wsr.windowstart a2
|
||||
rsync
|
||||
|
||||
// Load new stack pointer.
|
||||
l32r sp, 1b
|
||||
|
||||
// Re-enable WOE.
|
||||
rsr.ps a2
|
||||
movi a3, PS_WOE
|
||||
or a2, a2, a3
|
||||
wsr.ps a2
|
||||
rsync
|
||||
|
||||
// Jump to the runtime start function written in Go.
|
||||
j main
|
||||
|
||||
.section .text.tinygo_scanCurrentStack
|
||||
.global tinygo_scanCurrentStack
|
||||
tinygo_scanCurrentStack:
|
||||
// TODO: save callee saved registers on the stack
|
||||
j tinygo_scanstack
|
||||
@@ -1,6 +0,0 @@
|
||||
|
||||
.section .text.tinygo_scanCurrentStack
|
||||
.global tinygo_scanCurrentStack
|
||||
tinygo_scanCurrentStack:
|
||||
// TODO: save callee saved registers on the stack
|
||||
j tinygo_scanstack
|
||||
@@ -1,29 +0,0 @@
|
||||
// Hand created file. DO NOT DELETE.
|
||||
// Hardfault aliases for definitions that have inconsistent naming (which are
|
||||
// auto-generated by gen-device-svd.go) among devices in package nxp.
|
||||
|
||||
// +build nxp,!mimxrt1062
|
||||
|
||||
package nxp
|
||||
|
||||
const (
|
||||
HardFault_CFSR_IACCVIOL = SystemControl_CFSR_IACCVIOL
|
||||
HardFault_CFSR_DACCVIOL = SystemControl_CFSR_DACCVIOL
|
||||
HardFault_CFSR_MUNSTKERR = SystemControl_CFSR_MUNSTKERR
|
||||
HardFault_CFSR_MSTKERR = SystemControl_CFSR_MSTKERR
|
||||
HardFault_CFSR_MLSPERR = SystemControl_CFSR_MLSPERR
|
||||
HardFault_CFSR_IBUSERR = SystemControl_CFSR_IBUSERR
|
||||
HardFault_CFSR_PRECISERR = SystemControl_CFSR_PRECISERR
|
||||
HardFault_CFSR_IMPRECISERR = SystemControl_CFSR_IMPRECISERR
|
||||
HardFault_CFSR_UNSTKERR = SystemControl_CFSR_UNSTKERR
|
||||
HardFault_CFSR_STKERR = SystemControl_CFSR_STKERR
|
||||
HardFault_CFSR_LSPERR = SystemControl_CFSR_LSPERR
|
||||
HardFault_CFSR_UNDEFINSTR = SystemControl_CFSR_UNDEFINSTR
|
||||
HardFault_CFSR_INVSTATE = SystemControl_CFSR_INVSTATE
|
||||
HardFault_CFSR_INVPC = SystemControl_CFSR_INVPC
|
||||
HardFault_CFSR_NOCP = SystemControl_CFSR_NOCP
|
||||
HardFault_CFSR_UNALIGNED = SystemControl_CFSR_UNALIGNED
|
||||
HardFault_CFSR_DIVBYZERO = SystemControl_CFSR_DIVBYZERO
|
||||
HardFault_CFSR_MMARVALID = SystemControl_CFSR_MMARVALID
|
||||
HardFault_CFSR_BFARVALID = SystemControl_CFSR_BFARVALID
|
||||
)
|
||||
@@ -1,529 +0,0 @@
|
||||
// Hand created file. DO NOT DELETE.
|
||||
// Type definitions, fields, and constants associated with various clocks and
|
||||
// peripherals of the NXP MIMXRT1062.
|
||||
|
||||
// +build nxp,mimxrt1062
|
||||
|
||||
package nxp
|
||||
|
||||
import (
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Clock represents an individual peripheral clock that may be enabled/disabled
|
||||
// at runtime. Clocks also have a method `Mux` for selecting the clock source
|
||||
// and a method `Div` for selecting the hardware divisor. Note that many
|
||||
// peripherals have an independent prescalar configuration applied to the output
|
||||
// of this divisor.
|
||||
type (
|
||||
Clock uint32
|
||||
ClockMode uint8
|
||||
)
|
||||
|
||||
// Enable activates or deactivates the clock gate of receiver Clock c.
|
||||
func (c Clock) Enable(enable bool) {
|
||||
if enable {
|
||||
c.setGate(clockNeededRunWait)
|
||||
} else {
|
||||
c.setGate(clockNotNeeded)
|
||||
}
|
||||
}
|
||||
|
||||
// Mux selects a clock source for the mux of the receiver Clock c.
|
||||
func (c Clock) Mux(mux uint32) { c.setCcm(mux) }
|
||||
|
||||
// Div configures the prescalar divisor of the receiver Clock c.
|
||||
func (c Clock) Div(div uint32) { c.setCcm(div) }
|
||||
|
||||
const (
|
||||
ClockModeRun ClockMode = 0 // Remain in run mode
|
||||
ClockModeWait ClockMode = 1 // Transfer to wait mode
|
||||
ClockModeStop ClockMode = 2 // Transfer to stop mode
|
||||
)
|
||||
|
||||
// Set configures the run mode of the MCU.
|
||||
func (m ClockMode) Set() {
|
||||
CCM.CLPCR.Set((CCM.CLPCR.Get() & ^uint32(CCM_CLPCR_LPM_Msk)) |
|
||||
((uint32(m) << CCM_CLPCR_LPM_Pos) & CCM_CLPCR_LPM_Msk))
|
||||
}
|
||||
|
||||
// Named oscillators
|
||||
const (
|
||||
ClockCpu Clock = 0x0 // CPU clock
|
||||
ClockAhb Clock = 0x1 // AHB clock
|
||||
ClockSemc Clock = 0x2 // SEMC clock
|
||||
ClockIpg Clock = 0x3 // IPG clock
|
||||
ClockPer Clock = 0x4 // PER clock
|
||||
ClockOsc Clock = 0x5 // OSC clock selected by PMU_LOWPWR_CTRL[OSC_SEL]
|
||||
ClockRtc Clock = 0x6 // RTC clock (RTCCLK)
|
||||
ClockArmPll Clock = 0x7 // ARMPLLCLK
|
||||
ClockUsb1Pll Clock = 0x8 // USB1PLLCLK
|
||||
ClockUsb1PllPfd0 Clock = 0x9 // USB1PLLPDF0CLK
|
||||
ClockUsb1PllPfd1 Clock = 0xA // USB1PLLPFD1CLK
|
||||
ClockUsb1PllPfd2 Clock = 0xB // USB1PLLPFD2CLK
|
||||
ClockUsb1PllPfd3 Clock = 0xC // USB1PLLPFD3CLK
|
||||
ClockUsb2Pll Clock = 0xD // USB2PLLCLK
|
||||
ClockSysPll Clock = 0xE // SYSPLLCLK
|
||||
ClockSysPllPfd0 Clock = 0xF // SYSPLLPDF0CLK
|
||||
ClockSysPllPfd1 Clock = 0x10 // SYSPLLPFD1CLK
|
||||
ClockSysPllPfd2 Clock = 0x11 // SYSPLLPFD2CLK
|
||||
ClockSysPllPfd3 Clock = 0x12 // SYSPLLPFD3CLK
|
||||
ClockEnetPll0 Clock = 0x13 // Enet PLLCLK ref_enetpll0
|
||||
ClockEnetPll1 Clock = 0x14 // Enet PLLCLK ref_enetpll1
|
||||
ClockEnetPll2 Clock = 0x15 // Enet PLLCLK ref_enetpll2
|
||||
ClockAudioPll Clock = 0x16 // Audio PLLCLK
|
||||
ClockVideoPll Clock = 0x17 // Video PLLCLK
|
||||
)
|
||||
|
||||
// Named clocks of integrated peripherals
|
||||
const (
|
||||
ClockIpAipsTz1 Clock = (0 << 8) | CCM_CCGR0_CG0_Pos // CCGR0, CG0
|
||||
ClockIpAipsTz2 Clock = (0 << 8) | CCM_CCGR0_CG1_Pos // CCGR0, CG1
|
||||
ClockIpMqs Clock = (0 << 8) | CCM_CCGR0_CG2_Pos // CCGR0, CG2
|
||||
ClockIpFlexSpiExsc Clock = (0 << 8) | CCM_CCGR0_CG3_Pos // CCGR0, CG3
|
||||
ClockIpSimMMain Clock = (0 << 8) | CCM_CCGR0_CG4_Pos // CCGR0, CG4
|
||||
ClockIpDcp Clock = (0 << 8) | CCM_CCGR0_CG5_Pos // CCGR0, CG5
|
||||
ClockIpLpuart3 Clock = (0 << 8) | CCM_CCGR0_CG6_Pos // CCGR0, CG6
|
||||
ClockIpCan1 Clock = (0 << 8) | CCM_CCGR0_CG7_Pos // CCGR0, CG7
|
||||
ClockIpCan1S Clock = (0 << 8) | CCM_CCGR0_CG8_Pos // CCGR0, CG8
|
||||
ClockIpCan2 Clock = (0 << 8) | CCM_CCGR0_CG9_Pos // CCGR0, CG9
|
||||
ClockIpCan2S Clock = (0 << 8) | CCM_CCGR0_CG10_Pos // CCGR0, CG10
|
||||
ClockIpTrace Clock = (0 << 8) | CCM_CCGR0_CG11_Pos // CCGR0, CG11
|
||||
ClockIpGpt2 Clock = (0 << 8) | CCM_CCGR0_CG12_Pos // CCGR0, CG12
|
||||
ClockIpGpt2S Clock = (0 << 8) | CCM_CCGR0_CG13_Pos // CCGR0, CG13
|
||||
ClockIpLpuart2 Clock = (0 << 8) | CCM_CCGR0_CG14_Pos // CCGR0, CG14
|
||||
ClockIpGpio2 Clock = (0 << 8) | CCM_CCGR0_CG15_Pos // CCGR0, CG15
|
||||
|
||||
ClockIpLpspi1 Clock = (1 << 8) | CCM_CCGR1_CG0_Pos // CCGR1, CG0
|
||||
ClockIpLpspi2 Clock = (1 << 8) | CCM_CCGR1_CG1_Pos // CCGR1, CG1
|
||||
ClockIpLpspi3 Clock = (1 << 8) | CCM_CCGR1_CG2_Pos // CCGR1, CG2
|
||||
ClockIpLpspi4 Clock = (1 << 8) | CCM_CCGR1_CG3_Pos // CCGR1, CG3
|
||||
ClockIpAdc2 Clock = (1 << 8) | CCM_CCGR1_CG4_Pos // CCGR1, CG4
|
||||
ClockIpEnet Clock = (1 << 8) | CCM_CCGR1_CG5_Pos // CCGR1, CG5
|
||||
ClockIpPit Clock = (1 << 8) | CCM_CCGR1_CG6_Pos // CCGR1, CG6
|
||||
ClockIpAoi2 Clock = (1 << 8) | CCM_CCGR1_CG7_Pos // CCGR1, CG7
|
||||
ClockIpAdc1 Clock = (1 << 8) | CCM_CCGR1_CG8_Pos // CCGR1, CG8
|
||||
ClockIpSemcExsc Clock = (1 << 8) | CCM_CCGR1_CG9_Pos // CCGR1, CG9
|
||||
ClockIpGpt1 Clock = (1 << 8) | CCM_CCGR1_CG10_Pos // CCGR1, CG10
|
||||
ClockIpGpt1S Clock = (1 << 8) | CCM_CCGR1_CG11_Pos // CCGR1, CG11
|
||||
ClockIpLpuart4 Clock = (1 << 8) | CCM_CCGR1_CG12_Pos // CCGR1, CG12
|
||||
ClockIpGpio1 Clock = (1 << 8) | CCM_CCGR1_CG13_Pos // CCGR1, CG13
|
||||
ClockIpCsu Clock = (1 << 8) | CCM_CCGR1_CG14_Pos // CCGR1, CG14
|
||||
ClockIpGpio5 Clock = (1 << 8) | CCM_CCGR1_CG15_Pos // CCGR1, CG15
|
||||
|
||||
ClockIpOcramExsc Clock = (2 << 8) | CCM_CCGR2_CG0_Pos // CCGR2, CG0
|
||||
ClockIpCsi Clock = (2 << 8) | CCM_CCGR2_CG1_Pos // CCGR2, CG1
|
||||
ClockIpIomuxcSnvs Clock = (2 << 8) | CCM_CCGR2_CG2_Pos // CCGR2, CG2
|
||||
ClockIpLpi2c1 Clock = (2 << 8) | CCM_CCGR2_CG3_Pos // CCGR2, CG3
|
||||
ClockIpLpi2c2 Clock = (2 << 8) | CCM_CCGR2_CG4_Pos // CCGR2, CG4
|
||||
ClockIpLpi2c3 Clock = (2 << 8) | CCM_CCGR2_CG5_Pos // CCGR2, CG5
|
||||
ClockIpOcotp Clock = (2 << 8) | CCM_CCGR2_CG6_Pos // CCGR2, CG6
|
||||
ClockIpXbar3 Clock = (2 << 8) | CCM_CCGR2_CG7_Pos // CCGR2, CG7
|
||||
ClockIpIpmux1 Clock = (2 << 8) | CCM_CCGR2_CG8_Pos // CCGR2, CG8
|
||||
ClockIpIpmux2 Clock = (2 << 8) | CCM_CCGR2_CG9_Pos // CCGR2, CG9
|
||||
ClockIpIpmux3 Clock = (2 << 8) | CCM_CCGR2_CG10_Pos // CCGR2, CG10
|
||||
ClockIpXbar1 Clock = (2 << 8) | CCM_CCGR2_CG11_Pos // CCGR2, CG11
|
||||
ClockIpXbar2 Clock = (2 << 8) | CCM_CCGR2_CG12_Pos // CCGR2, CG12
|
||||
ClockIpGpio3 Clock = (2 << 8) | CCM_CCGR2_CG13_Pos // CCGR2, CG13
|
||||
ClockIpLcd Clock = (2 << 8) | CCM_CCGR2_CG14_Pos // CCGR2, CG14
|
||||
ClockIpPxp Clock = (2 << 8) | CCM_CCGR2_CG15_Pos // CCGR2, CG15
|
||||
|
||||
ClockIpFlexio2 Clock = (3 << 8) | CCM_CCGR3_CG0_Pos // CCGR3, CG0
|
||||
ClockIpLpuart5 Clock = (3 << 8) | CCM_CCGR3_CG1_Pos // CCGR3, CG1
|
||||
ClockIpSemc Clock = (3 << 8) | CCM_CCGR3_CG2_Pos // CCGR3, CG2
|
||||
ClockIpLpuart6 Clock = (3 << 8) | CCM_CCGR3_CG3_Pos // CCGR3, CG3
|
||||
ClockIpAoi1 Clock = (3 << 8) | CCM_CCGR3_CG4_Pos // CCGR3, CG4
|
||||
ClockIpLcdPixel Clock = (3 << 8) | CCM_CCGR3_CG5_Pos // CCGR3, CG5
|
||||
ClockIpGpio4 Clock = (3 << 8) | CCM_CCGR3_CG6_Pos // CCGR3, CG6
|
||||
ClockIpEwm0 Clock = (3 << 8) | CCM_CCGR3_CG7_Pos // CCGR3, CG7
|
||||
ClockIpWdog1 Clock = (3 << 8) | CCM_CCGR3_CG8_Pos // CCGR3, CG8
|
||||
ClockIpFlexRam Clock = (3 << 8) | CCM_CCGR3_CG9_Pos // CCGR3, CG9
|
||||
ClockIpAcmp1 Clock = (3 << 8) | CCM_CCGR3_CG10_Pos // CCGR3, CG10
|
||||
ClockIpAcmp2 Clock = (3 << 8) | CCM_CCGR3_CG11_Pos // CCGR3, CG11
|
||||
ClockIpAcmp3 Clock = (3 << 8) | CCM_CCGR3_CG12_Pos // CCGR3, CG12
|
||||
ClockIpAcmp4 Clock = (3 << 8) | CCM_CCGR3_CG13_Pos // CCGR3, CG13
|
||||
ClockIpOcram Clock = (3 << 8) | CCM_CCGR3_CG14_Pos // CCGR3, CG14
|
||||
ClockIpIomuxcSnvsGpr Clock = (3 << 8) | CCM_CCGR3_CG15_Pos // CCGR3, CG15
|
||||
|
||||
ClockIpIomuxc Clock = (4 << 8) | CCM_CCGR4_CG1_Pos // CCGR4, CG1
|
||||
ClockIpIomuxcGpr Clock = (4 << 8) | CCM_CCGR4_CG2_Pos // CCGR4, CG2
|
||||
ClockIpBee Clock = (4 << 8) | CCM_CCGR4_CG3_Pos // CCGR4, CG3
|
||||
ClockIpSimM7 Clock = (4 << 8) | CCM_CCGR4_CG4_Pos // CCGR4, CG4
|
||||
ClockIpTsc Clock = (4 << 8) | CCM_CCGR4_CG5_Pos // CCGR4, CG5
|
||||
ClockIpSimM Clock = (4 << 8) | CCM_CCGR4_CG6_Pos // CCGR4, CG6
|
||||
ClockIpSimEms Clock = (4 << 8) | CCM_CCGR4_CG7_Pos // CCGR4, CG7
|
||||
ClockIpPwm1 Clock = (4 << 8) | CCM_CCGR4_CG8_Pos // CCGR4, CG8
|
||||
ClockIpPwm2 Clock = (4 << 8) | CCM_CCGR4_CG9_Pos // CCGR4, CG9
|
||||
ClockIpPwm3 Clock = (4 << 8) | CCM_CCGR4_CG10_Pos // CCGR4, CG10
|
||||
ClockIpPwm4 Clock = (4 << 8) | CCM_CCGR4_CG11_Pos // CCGR4, CG11
|
||||
ClockIpEnc1 Clock = (4 << 8) | CCM_CCGR4_CG12_Pos // CCGR4, CG12
|
||||
ClockIpEnc2 Clock = (4 << 8) | CCM_CCGR4_CG13_Pos // CCGR4, CG13
|
||||
ClockIpEnc3 Clock = (4 << 8) | CCM_CCGR4_CG14_Pos // CCGR4, CG14
|
||||
ClockIpEnc4 Clock = (4 << 8) | CCM_CCGR4_CG15_Pos // CCGR4, CG15
|
||||
|
||||
ClockIpRom Clock = (5 << 8) | CCM_CCGR5_CG0_Pos // CCGR5, CG0
|
||||
ClockIpFlexio1 Clock = (5 << 8) | CCM_CCGR5_CG1_Pos // CCGR5, CG1
|
||||
ClockIpWdog3 Clock = (5 << 8) | CCM_CCGR5_CG2_Pos // CCGR5, CG2
|
||||
ClockIpDma Clock = (5 << 8) | CCM_CCGR5_CG3_Pos // CCGR5, CG3
|
||||
ClockIpKpp Clock = (5 << 8) | CCM_CCGR5_CG4_Pos // CCGR5, CG4
|
||||
ClockIpWdog2 Clock = (5 << 8) | CCM_CCGR5_CG5_Pos // CCGR5, CG5
|
||||
ClockIpAipsTz4 Clock = (5 << 8) | CCM_CCGR5_CG6_Pos // CCGR5, CG6
|
||||
ClockIpSpdif Clock = (5 << 8) | CCM_CCGR5_CG7_Pos // CCGR5, CG7
|
||||
ClockIpSimMain Clock = (5 << 8) | CCM_CCGR5_CG8_Pos // CCGR5, CG8
|
||||
ClockIpSai1 Clock = (5 << 8) | CCM_CCGR5_CG9_Pos // CCGR5, CG9
|
||||
ClockIpSai2 Clock = (5 << 8) | CCM_CCGR5_CG10_Pos // CCGR5, CG10
|
||||
ClockIpSai3 Clock = (5 << 8) | CCM_CCGR5_CG11_Pos // CCGR5, CG11
|
||||
ClockIpLpuart1 Clock = (5 << 8) | CCM_CCGR5_CG12_Pos // CCGR5, CG12
|
||||
ClockIpLpuart7 Clock = (5 << 8) | CCM_CCGR5_CG13_Pos // CCGR5, CG13
|
||||
ClockIpSnvsHp Clock = (5 << 8) | CCM_CCGR5_CG14_Pos // CCGR5, CG14
|
||||
ClockIpSnvsLp Clock = (5 << 8) | CCM_CCGR5_CG15_Pos // CCGR5, CG15
|
||||
|
||||
ClockIpUsbOh3 Clock = (6 << 8) | CCM_CCGR6_CG0_Pos // CCGR6, CG0
|
||||
ClockIpUsdhc1 Clock = (6 << 8) | CCM_CCGR6_CG1_Pos // CCGR6, CG1
|
||||
ClockIpUsdhc2 Clock = (6 << 8) | CCM_CCGR6_CG2_Pos // CCGR6, CG2
|
||||
ClockIpDcdc Clock = (6 << 8) | CCM_CCGR6_CG3_Pos // CCGR6, CG3
|
||||
ClockIpIpmux4 Clock = (6 << 8) | CCM_CCGR6_CG4_Pos // CCGR6, CG4
|
||||
ClockIpFlexSpi Clock = (6 << 8) | CCM_CCGR6_CG5_Pos // CCGR6, CG5
|
||||
ClockIpTrng Clock = (6 << 8) | CCM_CCGR6_CG6_Pos // CCGR6, CG6
|
||||
ClockIpLpuart8 Clock = (6 << 8) | CCM_CCGR6_CG7_Pos // CCGR6, CG7
|
||||
ClockIpTimer4 Clock = (6 << 8) | CCM_CCGR6_CG8_Pos // CCGR6, CG8
|
||||
ClockIpAipsTz3 Clock = (6 << 8) | CCM_CCGR6_CG9_Pos // CCGR6, CG9
|
||||
ClockIpSimPer Clock = (6 << 8) | CCM_CCGR6_CG10_Pos // CCGR6, CG10
|
||||
ClockIpAnadig Clock = (6 << 8) | CCM_CCGR6_CG11_Pos // CCGR6, CG11
|
||||
ClockIpLpi2c4 Clock = (6 << 8) | CCM_CCGR6_CG12_Pos // CCGR6, CG12
|
||||
ClockIpTimer1 Clock = (6 << 8) | CCM_CCGR6_CG13_Pos // CCGR6, CG13
|
||||
ClockIpTimer2 Clock = (6 << 8) | CCM_CCGR6_CG14_Pos // CCGR6, CG14
|
||||
ClockIpTimer3 Clock = (6 << 8) | CCM_CCGR6_CG15_Pos // CCGR6, CG15
|
||||
|
||||
ClockIpEnet2 Clock = (7 << 8) | CCM_CCGR7_CG0_Pos // CCGR7, CG0
|
||||
ClockIpFlexSpi2 Clock = (7 << 8) | CCM_CCGR7_CG1_Pos // CCGR7, CG1
|
||||
ClockIpAxbsL Clock = (7 << 8) | CCM_CCGR7_CG2_Pos // CCGR7, CG2
|
||||
ClockIpCan3 Clock = (7 << 8) | CCM_CCGR7_CG3_Pos // CCGR7, CG3
|
||||
ClockIpCan3S Clock = (7 << 8) | CCM_CCGR7_CG4_Pos // CCGR7, CG4
|
||||
ClockIpAipsLite Clock = (7 << 8) | CCM_CCGR7_CG5_Pos // CCGR7, CG5
|
||||
ClockIpFlexio3 Clock = (7 << 8) | CCM_CCGR7_CG6_Pos // CCGR7, CG6
|
||||
)
|
||||
|
||||
// PLL name
|
||||
const (
|
||||
ClockPllArm Clock = ((offPllArm & 0xFFF) << 16) | CCM_ANALOG_PLL_ARM_ENABLE_Pos // PLL ARM
|
||||
ClockPllSys Clock = ((offPllSys & 0xFFF) << 16) | CCM_ANALOG_PLL_SYS_ENABLE_Pos // PLL SYS
|
||||
ClockPllUsb1 Clock = ((offPllUsb1 & 0xFFF) << 16) | CCM_ANALOG_PLL_USB1_ENABLE_Pos // PLL USB1
|
||||
ClockPllAudio Clock = ((offPllAudio & 0xFFF) << 16) | CCM_ANALOG_PLL_AUDIO_ENABLE_Pos // PLL Audio
|
||||
ClockPllVideo Clock = ((offPllVideo & 0xFFF) << 16) | CCM_ANALOG_PLL_VIDEO_ENABLE_Pos // PLL Video
|
||||
ClockPllEnet Clock = ((offPllEnet & 0xFFF) << 16) | CCM_ANALOG_PLL_ENET_ENABLE_Pos // PLL Enet0
|
||||
ClockPllEnet2 Clock = ((offPllEnet & 0xFFF) << 16) | CCM_ANALOG_PLL_ENET_ENET2_REF_EN_Pos // PLL Enet1
|
||||
ClockPllEnet25M Clock = ((offPllEnet & 0xFFF) << 16) | CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_Pos // PLL Enet2
|
||||
ClockPllUsb2 Clock = ((offPllUsb2 & 0xFFF) << 16) | CCM_ANALOG_PLL_USB2_ENABLE_Pos // PLL USB2
|
||||
)
|
||||
|
||||
// PLL PFD name
|
||||
const (
|
||||
ClockPfd0 Clock = 0 // PLL PFD0
|
||||
ClockPfd1 Clock = 1 // PLL PFD1
|
||||
ClockPfd2 Clock = 2 // PLL PFD2
|
||||
ClockPfd3 Clock = 3 // PLL PFD3
|
||||
)
|
||||
|
||||
// Named clock muxes of integrated peripherals
|
||||
const (
|
||||
MuxIpPll3Sw Clock = (offCCSR & 0xFF) | (CCM_CCSR_PLL3_SW_CLK_SEL_Pos << 8) | (((CCM_CCSR_PLL3_SW_CLK_SEL_Msk >> CCM_CCSR_PLL3_SW_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // pll3_sw_clk mux name
|
||||
MuxIpPeriph Clock = (offCBCDR & 0xFF) | (CCM_CBCDR_PERIPH_CLK_SEL_Pos << 8) | (((CCM_CBCDR_PERIPH_CLK_SEL_Msk >> CCM_CBCDR_PERIPH_CLK_SEL_Pos) & 0x1FFF) << 13) | (CCM_CDHIPR_PERIPH_CLK_SEL_BUSY_Pos << 26) // periph mux name
|
||||
MuxIpSemcAlt Clock = (offCBCDR & 0xFF) | (CCM_CBCDR_SEMC_ALT_CLK_SEL_Pos << 8) | (((CCM_CBCDR_SEMC_ALT_CLK_SEL_Msk >> CCM_CBCDR_SEMC_ALT_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // semc mux name
|
||||
MuxIpSemc Clock = (offCBCDR & 0xFF) | (CCM_CBCDR_SEMC_CLK_SEL_Pos << 8) | (((CCM_CBCDR_SEMC_CLK_SEL_Msk >> CCM_CBCDR_SEMC_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // semc mux name
|
||||
MuxIpPrePeriph Clock = (offCBCMR & 0xFF) | (CCM_CBCMR_PRE_PERIPH_CLK_SEL_Pos << 8) | (((CCM_CBCMR_PRE_PERIPH_CLK_SEL_Msk >> CCM_CBCMR_PRE_PERIPH_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // pre-periph mux name
|
||||
MuxIpTrace Clock = (offCBCMR & 0xFF) | (CCM_CBCMR_TRACE_CLK_SEL_Pos << 8) | (((CCM_CBCMR_TRACE_CLK_SEL_Msk >> CCM_CBCMR_TRACE_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // trace mux name
|
||||
MuxIpPeriphClk2 Clock = (offCBCMR & 0xFF) | (CCM_CBCMR_PERIPH_CLK2_SEL_Pos << 8) | (((CCM_CBCMR_PERIPH_CLK2_SEL_Msk >> CCM_CBCMR_PERIPH_CLK2_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // periph clock2 mux name
|
||||
MuxIpFlexSpi2 Clock = (offCBCMR & 0xFF) | (CCM_CBCMR_FLEXSPI2_CLK_SEL_Pos << 8) | (((CCM_CBCMR_FLEXSPI2_CLK_SEL_Msk >> CCM_CBCMR_FLEXSPI2_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // flexspi2 mux name
|
||||
MuxIpLpspi Clock = (offCBCMR & 0xFF) | (CCM_CBCMR_LPSPI_CLK_SEL_Pos << 8) | (((CCM_CBCMR_LPSPI_CLK_SEL_Msk >> CCM_CBCMR_LPSPI_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // lpspi mux name
|
||||
MuxIpFlexSpi Clock = (offCSCMR1 & 0xFF) | (CCM_CSCMR1_FLEXSPI_CLK_SEL_Pos << 8) | (((CCM_CSCMR1_FLEXSPI_CLK_SEL_Msk >> CCM_CSCMR1_FLEXSPI_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // flexspi mux name
|
||||
MuxIpUsdhc2 Clock = (offCSCMR1 & 0xFF) | (CCM_CSCMR1_USDHC2_CLK_SEL_Pos << 8) | (((CCM_CSCMR1_USDHC2_CLK_SEL_Msk >> CCM_CSCMR1_USDHC2_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // usdhc2 mux name
|
||||
MuxIpUsdhc1 Clock = (offCSCMR1 & 0xFF) | (CCM_CSCMR1_USDHC1_CLK_SEL_Pos << 8) | (((CCM_CSCMR1_USDHC1_CLK_SEL_Msk >> CCM_CSCMR1_USDHC1_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // usdhc1 mux name
|
||||
MuxIpSai3 Clock = (offCSCMR1 & 0xFF) | (CCM_CSCMR1_SAI3_CLK_SEL_Pos << 8) | (((CCM_CSCMR1_SAI3_CLK_SEL_Msk >> CCM_CSCMR1_SAI3_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // sai3 mux name
|
||||
MuxIpSai2 Clock = (offCSCMR1 & 0xFF) | (CCM_CSCMR1_SAI2_CLK_SEL_Pos << 8) | (((CCM_CSCMR1_SAI2_CLK_SEL_Msk >> CCM_CSCMR1_SAI2_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // sai2 mux name
|
||||
MuxIpSai1 Clock = (offCSCMR1 & 0xFF) | (CCM_CSCMR1_SAI1_CLK_SEL_Pos << 8) | (((CCM_CSCMR1_SAI1_CLK_SEL_Msk >> CCM_CSCMR1_SAI1_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // sai1 mux name
|
||||
MuxIpPerclk Clock = (offCSCMR1 & 0xFF) | (CCM_CSCMR1_PERCLK_CLK_SEL_Pos << 8) | (((CCM_CSCMR1_PERCLK_CLK_SEL_Msk >> CCM_CSCMR1_PERCLK_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // perclk mux name
|
||||
MuxIpFlexio2 Clock = (offCSCMR2 & 0xFF) | (CCM_CSCMR2_FLEXIO2_CLK_SEL_Pos << 8) | (((CCM_CSCMR2_FLEXIO2_CLK_SEL_Msk >> CCM_CSCMR2_FLEXIO2_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // flexio2 mux name
|
||||
MuxIpCan Clock = (offCSCMR2 & 0xFF) | (CCM_CSCMR2_CAN_CLK_SEL_Pos << 8) | (((CCM_CSCMR2_CAN_CLK_SEL_Msk >> CCM_CSCMR2_CAN_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // can mux name
|
||||
MuxIpUart Clock = (offCSCDR1 & 0xFF) | (CCM_CSCDR1_UART_CLK_SEL_Pos << 8) | (((CCM_CSCDR1_UART_CLK_SEL_Msk >> CCM_CSCDR1_UART_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // uart mux name
|
||||
MuxIpSpdif Clock = (offCDCDR & 0xFF) | (CCM_CDCDR_SPDIF0_CLK_SEL_Pos << 8) | (((CCM_CDCDR_SPDIF0_CLK_SEL_Msk >> CCM_CDCDR_SPDIF0_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // spdif mux name
|
||||
MuxIpFlexio1 Clock = (offCDCDR & 0xFF) | (CCM_CDCDR_FLEXIO1_CLK_SEL_Pos << 8) | (((CCM_CDCDR_FLEXIO1_CLK_SEL_Msk >> CCM_CDCDR_FLEXIO1_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // flexio1 mux name
|
||||
MuxIpLpi2c Clock = (offCSCDR2 & 0xFF) | (CCM_CSCDR2_LPI2C_CLK_SEL_Pos << 8) | (((CCM_CSCDR2_LPI2C_CLK_SEL_Msk >> CCM_CSCDR2_LPI2C_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // lpi2c mux name
|
||||
MuxIpLcdifPre Clock = (offCSCDR2 & 0xFF) | (CCM_CSCDR2_LCDIF_PRE_CLK_SEL_Pos << 8) | (((CCM_CSCDR2_LCDIF_PRE_CLK_SEL_Msk >> CCM_CSCDR2_LCDIF_PRE_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // lcdif pre mux name
|
||||
MuxIpCsi Clock = (offCSCDR3 & 0xFF) | (CCM_CSCDR3_CSI_CLK_SEL_Pos << 8) | (((CCM_CSCDR3_CSI_CLK_SEL_Msk >> CCM_CSCDR3_CSI_CLK_SEL_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // csi mux name
|
||||
)
|
||||
|
||||
// Named hardware clock divisors of integrated peripherals
|
||||
const (
|
||||
DivIpArm Clock = (offCACRR & 0xFF) | (CCM_CACRR_ARM_PODF_Pos << 8) | (((CCM_CACRR_ARM_PODF_Msk >> CCM_CACRR_ARM_PODF_Pos) & 0x1FFF) << 13) | (CCM_CDHIPR_ARM_PODF_BUSY_Pos << 26) // core div name
|
||||
DivIpPeriphClk2 Clock = (offCBCDR & 0xFF) | (CCM_CBCDR_PERIPH_CLK2_PODF_Pos << 8) | (((CCM_CBCDR_PERIPH_CLK2_PODF_Msk >> CCM_CBCDR_PERIPH_CLK2_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // periph clock2 div name
|
||||
DivIpSemc Clock = (offCBCDR & 0xFF) | (CCM_CBCDR_SEMC_PODF_Pos << 8) | (((CCM_CBCDR_SEMC_PODF_Msk >> CCM_CBCDR_SEMC_PODF_Pos) & 0x1FFF) << 13) | (CCM_CDHIPR_SEMC_PODF_BUSY_Pos << 26) // semc div name
|
||||
DivIpAhb Clock = (offCBCDR & 0xFF) | (CCM_CBCDR_AHB_PODF_Pos << 8) | (((CCM_CBCDR_AHB_PODF_Msk >> CCM_CBCDR_AHB_PODF_Pos) & 0x1FFF) << 13) | (CCM_CDHIPR_AHB_PODF_BUSY_Pos << 26) // ahb div name
|
||||
DivIpIpg Clock = (offCBCDR & 0xFF) | (CCM_CBCDR_IPG_PODF_Pos << 8) | (((CCM_CBCDR_IPG_PODF_Msk >> CCM_CBCDR_IPG_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // ipg div name
|
||||
DivIpFlexSpi2 Clock = (offCBCMR & 0xFF) | (CCM_CBCMR_FLEXSPI2_PODF_Pos << 8) | (((CCM_CBCMR_FLEXSPI2_PODF_Msk >> CCM_CBCMR_FLEXSPI2_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // flexspi2 div name
|
||||
DivIpLpspi Clock = (offCBCMR & 0xFF) | (CCM_CBCMR_LPSPI_PODF_Pos << 8) | (((CCM_CBCMR_LPSPI_PODF_Msk >> CCM_CBCMR_LPSPI_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // lpspi div name
|
||||
DivIpLcdif Clock = (offCBCMR & 0xFF) | (CCM_CBCMR_LCDIF_PODF_Pos << 8) | (((CCM_CBCMR_LCDIF_PODF_Msk >> CCM_CBCMR_LCDIF_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // lcdif div name
|
||||
DivIpFlexSpi Clock = (offCSCMR1 & 0xFF) | (CCM_CSCMR1_FLEXSPI_PODF_Pos << 8) | (((CCM_CSCMR1_FLEXSPI_PODF_Msk >> CCM_CSCMR1_FLEXSPI_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // flexspi div name
|
||||
DivIpPerclk Clock = (offCSCMR1 & 0xFF) | (CCM_CSCMR1_PERCLK_PODF_Pos << 8) | (((CCM_CSCMR1_PERCLK_PODF_Msk >> CCM_CSCMR1_PERCLK_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // perclk div name
|
||||
DivIpCan Clock = (offCSCMR2 & 0xFF) | (CCM_CSCMR2_CAN_CLK_PODF_Pos << 8) | (((CCM_CSCMR2_CAN_CLK_PODF_Msk >> CCM_CSCMR2_CAN_CLK_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // can div name
|
||||
DivIpTrace Clock = (offCSCDR1 & 0xFF) | (CCM_CSCDR1_TRACE_PODF_Pos << 8) | (((CCM_CSCDR1_TRACE_PODF_Msk >> CCM_CSCDR1_TRACE_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // trace div name
|
||||
DivIpUsdhc2 Clock = (offCSCDR1 & 0xFF) | (CCM_CSCDR1_USDHC2_PODF_Pos << 8) | (((CCM_CSCDR1_USDHC2_PODF_Msk >> CCM_CSCDR1_USDHC2_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // usdhc2 div name
|
||||
DivIpUsdhc1 Clock = (offCSCDR1 & 0xFF) | (CCM_CSCDR1_USDHC1_PODF_Pos << 8) | (((CCM_CSCDR1_USDHC1_PODF_Msk >> CCM_CSCDR1_USDHC1_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // usdhc1 div name
|
||||
DivIpUart Clock = (offCSCDR1 & 0xFF) | (CCM_CSCDR1_UART_CLK_PODF_Pos << 8) | (((CCM_CSCDR1_UART_CLK_PODF_Msk >> CCM_CSCDR1_UART_CLK_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // uart div name
|
||||
DivIpFlexio2 Clock = (offCS1CDR & 0xFF) | (CCM_CS1CDR_FLEXIO2_CLK_PODF_Pos << 8) | (((CCM_CS1CDR_FLEXIO2_CLK_PODF_Msk >> CCM_CS1CDR_FLEXIO2_CLK_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // flexio2 pre div name
|
||||
DivIpSai3Pre Clock = (offCS1CDR & 0xFF) | (CCM_CS1CDR_SAI3_CLK_PRED_Pos << 8) | (((CCM_CS1CDR_SAI3_CLK_PRED_Msk >> CCM_CS1CDR_SAI3_CLK_PRED_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // sai3 pre div name
|
||||
DivIpSai3 Clock = (offCS1CDR & 0xFF) | (CCM_CS1CDR_SAI3_CLK_PODF_Pos << 8) | (((CCM_CS1CDR_SAI3_CLK_PODF_Msk >> CCM_CS1CDR_SAI3_CLK_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // sai3 div name
|
||||
DivIpFlexio2Pre Clock = (offCS1CDR & 0xFF) | (CCM_CS1CDR_FLEXIO2_CLK_PRED_Pos << 8) | (((CCM_CS1CDR_FLEXIO2_CLK_PRED_Msk >> CCM_CS1CDR_FLEXIO2_CLK_PRED_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // sai3 pre div name
|
||||
DivIpSai1Pre Clock = (offCS1CDR & 0xFF) | (CCM_CS1CDR_SAI1_CLK_PRED_Pos << 8) | (((CCM_CS1CDR_SAI1_CLK_PRED_Msk >> CCM_CS1CDR_SAI1_CLK_PRED_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // sai1 pre div name
|
||||
DivIpSai1 Clock = (offCS1CDR & 0xFF) | (CCM_CS1CDR_SAI1_CLK_PODF_Pos << 8) | (((CCM_CS1CDR_SAI1_CLK_PODF_Msk >> CCM_CS1CDR_SAI1_CLK_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // sai1 div name
|
||||
DivIpSai2Pre Clock = (offCS2CDR & 0xFF) | (CCM_CS2CDR_SAI2_CLK_PRED_Pos << 8) | (((CCM_CS2CDR_SAI2_CLK_PRED_Msk >> CCM_CS2CDR_SAI2_CLK_PRED_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // sai2 pre div name
|
||||
DivIpSai2 Clock = (offCS2CDR & 0xFF) | (CCM_CS2CDR_SAI2_CLK_PODF_Pos << 8) | (((CCM_CS2CDR_SAI2_CLK_PODF_Msk >> CCM_CS2CDR_SAI2_CLK_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // sai2 div name
|
||||
DivIpSpdif0Pre Clock = (offCDCDR & 0xFF) | (CCM_CDCDR_SPDIF0_CLK_PRED_Pos << 8) | (((CCM_CDCDR_SPDIF0_CLK_PRED_Msk >> CCM_CDCDR_SPDIF0_CLK_PRED_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // spdif pre div name
|
||||
DivIpSpdif0 Clock = (offCDCDR & 0xFF) | (CCM_CDCDR_SPDIF0_CLK_PODF_Pos << 8) | (((CCM_CDCDR_SPDIF0_CLK_PODF_Msk >> CCM_CDCDR_SPDIF0_CLK_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // spdif div name
|
||||
DivIpFlexio1Pre Clock = (offCDCDR & 0xFF) | (CCM_CDCDR_FLEXIO1_CLK_PRED_Pos << 8) | (((CCM_CDCDR_FLEXIO1_CLK_PRED_Msk >> CCM_CDCDR_FLEXIO1_CLK_PRED_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // flexio1 pre div name
|
||||
DivIpFlexio1 Clock = (offCDCDR & 0xFF) | (CCM_CDCDR_FLEXIO1_CLK_PODF_Pos << 8) | (((CCM_CDCDR_FLEXIO1_CLK_PODF_Msk >> CCM_CDCDR_FLEXIO1_CLK_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // flexio1 div name
|
||||
DivIpLpi2c Clock = (offCSCDR2 & 0xFF) | (CCM_CSCDR2_LPI2C_CLK_PODF_Pos << 8) | (((CCM_CSCDR2_LPI2C_CLK_PODF_Msk >> CCM_CSCDR2_LPI2C_CLK_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // lpi2c div name
|
||||
DivIpLcdifPre Clock = (offCSCDR2 & 0xFF) | (CCM_CSCDR2_LCDIF_PRED_Pos << 8) | (((CCM_CSCDR2_LCDIF_PRED_Msk >> CCM_CSCDR2_LCDIF_PRED_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // lcdif pre div name
|
||||
DivIpCsi Clock = (offCSCDR3 & 0xFF) | (CCM_CSCDR3_CSI_PODF_Pos << 8) | (((CCM_CSCDR3_CSI_PODF_Msk >> CCM_CSCDR3_CSI_PODF_Pos) & 0x1FFF) << 13) | (noBusyWait << 26) // csi div name
|
||||
)
|
||||
|
||||
// Selected clock offsets
|
||||
const (
|
||||
offCCSR = 0x0C
|
||||
offCBCDR = 0x14
|
||||
offCBCMR = 0x18
|
||||
offCSCMR1 = 0x1C
|
||||
offCSCMR2 = 0x20
|
||||
offCSCDR1 = 0x24
|
||||
offCDCDR = 0x30
|
||||
offCSCDR2 = 0x38
|
||||
offCSCDR3 = 0x3C
|
||||
offCACRR = 0x10
|
||||
offCS1CDR = 0x28
|
||||
offCS2CDR = 0x2C
|
||||
|
||||
offPllArm = 0x00
|
||||
offPllSys = 0x30
|
||||
offPllUsb1 = 0x10
|
||||
offPllAudio = 0x70
|
||||
offPllVideo = 0xA0
|
||||
offPllEnet = 0xE0
|
||||
offPllUsb2 = 0x20
|
||||
|
||||
noBusyWait = 0x20
|
||||
)
|
||||
|
||||
// analog PLL definition
|
||||
const (
|
||||
pllBypassPos = 16
|
||||
pllBypassClkSrcMsk = 0xC000
|
||||
pllBypassClkSrcPos = 14
|
||||
)
|
||||
|
||||
// PLL clock source, bypass cloco source also
|
||||
const (
|
||||
pllSrc24M = 0 // Pll clock source 24M
|
||||
pllSrcClkPN = 1 // Pll clock source CLK1_P and CLK1_N
|
||||
)
|
||||
|
||||
const (
|
||||
clockNotNeeded uint32 = 0 // Clock is off during all modes
|
||||
clockNeededRun uint32 = 1 // Clock is on in run mode, but off in WAIT and STOP modes
|
||||
clockNeededRunWait uint32 = 3 // Clock is on during all modes, except STOP mode
|
||||
)
|
||||
|
||||
// getGate returns the CCM clock gating register for the receiver clk.
|
||||
func (clk Clock) getGate() *volatile.Register32 {
|
||||
switch clk >> 8 {
|
||||
case 0:
|
||||
return &CCM.CCGR0
|
||||
case 1:
|
||||
return &CCM.CCGR1
|
||||
case 2:
|
||||
return &CCM.CCGR2
|
||||
case 3:
|
||||
return &CCM.CCGR3
|
||||
case 4:
|
||||
return &CCM.CCGR4
|
||||
case 5:
|
||||
return &CCM.CCGR5
|
||||
case 6:
|
||||
return &CCM.CCGR6
|
||||
case 7:
|
||||
return &CCM.CCGR7
|
||||
default:
|
||||
panic("nxp: invalid clock")
|
||||
}
|
||||
}
|
||||
|
||||
// setGate enables or disables the receiver clk using its gating register.
|
||||
func (clk Clock) setGate(value uint32) {
|
||||
reg := clk.getGate()
|
||||
shift := clk & 0x1F
|
||||
reg.Set((reg.Get() & ^(3 << shift)) | (value << shift))
|
||||
}
|
||||
|
||||
func (clk Clock) setCcm(value uint32) {
|
||||
const ccmBase = 0x400fc000
|
||||
reg := (*volatile.Register32)(unsafe.Pointer(uintptr(ccmBase + (uint32(clk) & 0xFF))))
|
||||
msk := ((uint32(clk) >> 13) & 0x1FFF) << ((uint32(clk) >> 8) & 0x1F)
|
||||
pos := (uint32(clk) >> 8) & 0x1F
|
||||
bsy := (uint32(clk) >> 26) & 0x3F
|
||||
reg.Set((reg.Get() & ^uint32(msk)) | ((value << pos) & msk))
|
||||
if bsy < noBusyWait {
|
||||
for CCM.CDHIPR.HasBits(1 << bsy) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setSysPfd(value ...uint32) {
|
||||
for i, val := range value {
|
||||
pfd528 := CCM_ANALOG.PFD_528.Get() &
|
||||
^((CCM_ANALOG_PFD_528_PFD0_CLKGATE_Msk | CCM_ANALOG_PFD_528_PFD0_FRAC_Msk) << (8 * uint32(i)))
|
||||
frac := (val << CCM_ANALOG_PFD_528_PFD0_FRAC_Pos) & CCM_ANALOG_PFD_528_PFD0_FRAC_Msk
|
||||
// disable the clock output first
|
||||
CCM_ANALOG.PFD_528.Set(pfd528 | (CCM_ANALOG_PFD_528_PFD0_CLKGATE_Msk << (8 * uint32(i))))
|
||||
// set the new value and enable output
|
||||
CCM_ANALOG.PFD_528.Set(pfd528 | (frac << (8 * uint32(i))))
|
||||
}
|
||||
}
|
||||
|
||||
func setUsb1Pfd(value ...uint32) {
|
||||
for i, val := range value {
|
||||
pfd480 := CCM_ANALOG.PFD_480.Get() &
|
||||
^((CCM_ANALOG_PFD_480_PFD0_CLKGATE_Msk | CCM_ANALOG_PFD_480_PFD0_FRAC_Msk) << (8 * uint32(i)))
|
||||
frac := (val << CCM_ANALOG_PFD_480_PFD0_FRAC_Pos) & CCM_ANALOG_PFD_480_PFD0_FRAC_Msk
|
||||
// disable the clock output first
|
||||
CCM_ANALOG.PFD_480.Set(pfd480 | (CCM_ANALOG_PFD_480_PFD0_CLKGATE_Msk << (8 * uint32(i))))
|
||||
// set the new value and enable output
|
||||
CCM_ANALOG.PFD_480.Set(pfd480 | (frac << (8 * uint32(i))))
|
||||
}
|
||||
}
|
||||
|
||||
// PLL configuration for ARM
|
||||
type ClockConfigArmPll struct {
|
||||
LoopDivider uint32 // PLL loop divider. Valid range for divider value: 54-108. Fout=Fin*LoopDivider/2.
|
||||
Src uint8 // Pll clock source, reference _clock_pll_clk_src
|
||||
}
|
||||
|
||||
func (cfg ClockConfigArmPll) Configure() {
|
||||
|
||||
// bypass PLL first
|
||||
src := (uint32(cfg.Src) << CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_Pos) & CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_Msk
|
||||
CCM_ANALOG.PLL_ARM.Set(
|
||||
(CCM_ANALOG.PLL_ARM.Get() & ^uint32(CCM_ANALOG_PLL_ARM_BYPASS_CLK_SRC_Msk)) |
|
||||
CCM_ANALOG_PLL_ARM_BYPASS_Msk | src)
|
||||
|
||||
sel := (cfg.LoopDivider << CCM_ANALOG_PLL_ARM_DIV_SELECT_Pos) & CCM_ANALOG_PLL_ARM_DIV_SELECT_Msk
|
||||
CCM_ANALOG.PLL_ARM.Set(
|
||||
(CCM_ANALOG.PLL_ARM.Get() & ^uint32(CCM_ANALOG_PLL_ARM_DIV_SELECT_Msk|CCM_ANALOG_PLL_ARM_POWERDOWN_Msk)) |
|
||||
CCM_ANALOG_PLL_ARM_ENABLE_Msk | sel)
|
||||
|
||||
for !CCM_ANALOG.PLL_ARM.HasBits(CCM_ANALOG_PLL_ARM_LOCK_Msk) {
|
||||
}
|
||||
|
||||
// disable bypass
|
||||
CCM_ANALOG.PLL_ARM.ClearBits(CCM_ANALOG_PLL_ARM_BYPASS_Msk)
|
||||
}
|
||||
|
||||
// PLL configuration for System
|
||||
type ClockConfigSysPll struct {
|
||||
LoopDivider uint8 // PLL loop divider. Intended to be 1 (528M): 0 - Fout=Fref*20, 1 - Fout=Fref*22
|
||||
Numerator uint32 // 30 bit Numerator of fractional loop divider.
|
||||
Denominator uint32 // 30 bit Denominator of fractional loop divider
|
||||
Src uint8 // Pll clock source, reference _clock_pll_clk_src
|
||||
SsStop uint16 // Stop value to get frequency change.
|
||||
SsEnable uint8 // Enable spread spectrum modulation
|
||||
SsStep uint16 // Step value to get frequency change step.
|
||||
}
|
||||
|
||||
func (cfg ClockConfigSysPll) Configure(pfd ...uint32) {
|
||||
|
||||
// bypass PLL first
|
||||
src := (uint32(cfg.Src) << CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_Pos) & CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_Msk
|
||||
CCM_ANALOG.PLL_SYS.Set(
|
||||
(CCM_ANALOG.PLL_SYS.Get() & ^uint32(CCM_ANALOG_PLL_SYS_BYPASS_CLK_SRC_Msk)) |
|
||||
CCM_ANALOG_PLL_SYS_BYPASS_Msk | src)
|
||||
|
||||
sel := (uint32(cfg.LoopDivider) << CCM_ANALOG_PLL_SYS_DIV_SELECT_Pos) & CCM_ANALOG_PLL_SYS_DIV_SELECT_Msk
|
||||
CCM_ANALOG.PLL_SYS.Set(
|
||||
(CCM_ANALOG.PLL_SYS.Get() & ^uint32(CCM_ANALOG_PLL_SYS_DIV_SELECT_Msk|CCM_ANALOG_PLL_SYS_POWERDOWN_Msk)) |
|
||||
CCM_ANALOG_PLL_SYS_ENABLE_Msk | sel)
|
||||
|
||||
// initialize the fractional mode
|
||||
CCM_ANALOG.PLL_SYS_NUM.Set((cfg.Numerator << CCM_ANALOG_PLL_SYS_NUM_A_Pos) & CCM_ANALOG_PLL_SYS_NUM_A_Msk)
|
||||
CCM_ANALOG.PLL_SYS_DENOM.Set((cfg.Denominator << CCM_ANALOG_PLL_SYS_DENOM_B_Pos) & CCM_ANALOG_PLL_SYS_DENOM_B_Msk)
|
||||
|
||||
// initialize the spread spectrum mode
|
||||
inc := (uint32(cfg.SsStep) << CCM_ANALOG_PLL_SYS_SS_STEP_Pos) & CCM_ANALOG_PLL_SYS_SS_STEP_Msk
|
||||
enb := (uint32(cfg.SsEnable) << CCM_ANALOG_PLL_SYS_SS_ENABLE_Pos) & CCM_ANALOG_PLL_SYS_SS_ENABLE_Msk
|
||||
stp := (uint32(cfg.SsStop) << CCM_ANALOG_PLL_SYS_SS_STOP_Pos) & CCM_ANALOG_PLL_SYS_SS_STOP_Msk
|
||||
CCM_ANALOG.PLL_SYS_SS.Set(inc | enb | stp)
|
||||
|
||||
for !CCM_ANALOG.PLL_SYS.HasBits(CCM_ANALOG_PLL_SYS_LOCK_Msk) {
|
||||
}
|
||||
|
||||
// disable bypass
|
||||
CCM_ANALOG.PLL_SYS.ClearBits(CCM_ANALOG_PLL_SYS_BYPASS_Msk)
|
||||
|
||||
// update PFDs after update
|
||||
setSysPfd(pfd...)
|
||||
}
|
||||
|
||||
// PLL configuration for USB
|
||||
type ClockConfigUsbPll struct {
|
||||
Instance uint8 // USB PLL number (1 or 2)
|
||||
LoopDivider uint8 // PLL loop divider: 0 - Fout=Fref*20, 1 - Fout=Fref*22
|
||||
Src uint8 // Pll clock source, reference _clock_pll_clk_src
|
||||
}
|
||||
|
||||
func (cfg ClockConfigUsbPll) Configure(pfd ...uint32) {
|
||||
|
||||
switch cfg.Instance {
|
||||
case 1:
|
||||
|
||||
// bypass PLL first
|
||||
src := (uint32(cfg.Src) << CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_Pos) & CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_Msk
|
||||
CCM_ANALOG.PLL_USB1.Set(
|
||||
(CCM_ANALOG.PLL_USB1.Get() & ^uint32(CCM_ANALOG_PLL_USB1_BYPASS_CLK_SRC_Msk)) |
|
||||
CCM_ANALOG_PLL_USB1_BYPASS_Msk | src)
|
||||
|
||||
sel := uint32((cfg.LoopDivider << CCM_ANALOG_PLL_USB1_DIV_SELECT_Pos) & CCM_ANALOG_PLL_USB1_DIV_SELECT_Msk)
|
||||
CCM_ANALOG.PLL_USB1_SET.Set(
|
||||
(CCM_ANALOG.PLL_USB1.Get() & ^uint32(CCM_ANALOG_PLL_USB1_DIV_SELECT_Msk)) |
|
||||
CCM_ANALOG_PLL_USB1_ENABLE_Msk | CCM_ANALOG_PLL_USB1_POWER_Msk |
|
||||
CCM_ANALOG_PLL_USB1_EN_USB_CLKS_Msk | sel)
|
||||
|
||||
for !CCM_ANALOG.PLL_USB1.HasBits(CCM_ANALOG_PLL_USB1_LOCK_Msk) {
|
||||
}
|
||||
|
||||
// disable bypass
|
||||
CCM_ANALOG.PLL_USB1_CLR.Set(CCM_ANALOG_PLL_USB1_BYPASS_Msk)
|
||||
|
||||
// update PFDs after update
|
||||
setUsb1Pfd(pfd...)
|
||||
|
||||
case 2:
|
||||
// bypass PLL first
|
||||
src := (uint32(cfg.Src) << CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_Pos) & CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_Msk
|
||||
CCM_ANALOG.PLL_USB2.Set(
|
||||
(CCM_ANALOG.PLL_USB2.Get() & ^uint32(CCM_ANALOG_PLL_USB2_BYPASS_CLK_SRC_Msk)) |
|
||||
CCM_ANALOG_PLL_USB2_BYPASS_Msk | src)
|
||||
|
||||
sel := uint32((cfg.LoopDivider << CCM_ANALOG_PLL_USB2_DIV_SELECT_Pos) & CCM_ANALOG_PLL_USB2_DIV_SELECT_Msk)
|
||||
CCM_ANALOG.PLL_USB2.Set(
|
||||
(CCM_ANALOG.PLL_USB2.Get() & ^uint32(CCM_ANALOG_PLL_USB2_DIV_SELECT_Msk)) |
|
||||
CCM_ANALOG_PLL_USB2_ENABLE_Msk | CCM_ANALOG_PLL_USB2_POWER_Msk |
|
||||
CCM_ANALOG_PLL_USB2_EN_USB_CLKS_Msk | sel)
|
||||
|
||||
for !CCM_ANALOG.PLL_USB2.HasBits(CCM_ANALOG_PLL_USB2_LOCK_Msk) {
|
||||
}
|
||||
|
||||
// disable bypass
|
||||
CCM_ANALOG.PLL_USB2.ClearBits(CCM_ANALOG_PLL_USB2_BYPASS_Msk)
|
||||
|
||||
default:
|
||||
panic("nxp: invalid USB PLL")
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
// Hand created file. DO NOT DELETE.
|
||||
// Hardfault aliases for definitions that have inconsistent naming (which are
|
||||
// auto-generated by gen-device-svd.go) among devices in package nxp.
|
||||
|
||||
// +build nxp,mimxrt1062
|
||||
|
||||
package nxp
|
||||
|
||||
const (
|
||||
HardFault_CFSR_IACCVIOL = SCB_CFSR_IACCVIOL
|
||||
HardFault_CFSR_DACCVIOL = SCB_CFSR_DACCVIOL
|
||||
HardFault_CFSR_MUNSTKERR = SCB_CFSR_MUNSTKERR
|
||||
HardFault_CFSR_MSTKERR = SCB_CFSR_MSTKERR
|
||||
HardFault_CFSR_MLSPERR = SCB_CFSR_MLSPERR
|
||||
HardFault_CFSR_IBUSERR = SCB_CFSR_IBUSERR
|
||||
HardFault_CFSR_PRECISERR = SCB_CFSR_PRECISERR
|
||||
HardFault_CFSR_IMPRECISERR = SCB_CFSR_IMPRECISERR
|
||||
HardFault_CFSR_UNSTKERR = SCB_CFSR_UNSTKERR
|
||||
HardFault_CFSR_STKERR = SCB_CFSR_STKERR
|
||||
HardFault_CFSR_LSPERR = SCB_CFSR_LSPERR
|
||||
HardFault_CFSR_UNDEFINSTR = SCB_CFSR_UNDEFINSTR
|
||||
HardFault_CFSR_INVSTATE = SCB_CFSR_INVSTATE
|
||||
HardFault_CFSR_INVPC = SCB_CFSR_INVPC
|
||||
HardFault_CFSR_NOCP = SCB_CFSR_NOCP
|
||||
HardFault_CFSR_UNALIGNED = SCB_CFSR_UNALIGNED
|
||||
HardFault_CFSR_DIVBYZERO = SCB_CFSR_DIVBYZERO
|
||||
HardFault_CFSR_MMARVALID = SCB_CFSR_MMARVALID
|
||||
HardFault_CFSR_BFARVALID = SCB_CFSR_BFARVALID
|
||||
)
|
||||
@@ -1,278 +0,0 @@
|
||||
// Hand created file. DO NOT DELETE.
|
||||
// Type definitions, fields, and constants associated with the MPU peripheral
|
||||
// of the NXP MIMXRT1062.
|
||||
|
||||
// +build nxp,mimxrt1062
|
||||
|
||||
package nxp
|
||||
|
||||
import (
|
||||
"device/arm"
|
||||
"runtime/volatile"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type MPU_Type struct {
|
||||
TYPE volatile.Register32 // 0x000 (R/ ) - MPU Type Register
|
||||
CTRL volatile.Register32 // 0x004 (R/W) - MPU Control Register
|
||||
RNR volatile.Register32 // 0x008 (R/W) - MPU Region RNRber Register
|
||||
RBAR volatile.Register32 // 0x00C (R/W) - MPU Region Base Address Register
|
||||
RASR volatile.Register32 // 0x010 (R/W) - MPU Region Attribute and Size Register
|
||||
RBAR_A1 volatile.Register32 // 0x014 (R/W) - MPU Alias 1 Region Base Address Register
|
||||
RASR_A1 volatile.Register32 // 0x018 (R/W) - MPU Alias 1 Region Attribute and Size Register
|
||||
RBAR_A2 volatile.Register32 // 0x01C (R/W) - MPU Alias 2 Region Base Address Register
|
||||
RASR_A2 volatile.Register32 // 0x020 (R/W) - MPU Alias 2 Region Attribute and Size Register
|
||||
RBAR_A3 volatile.Register32 // 0x024 (R/W) - MPU Alias 3 Region Base Address Register
|
||||
RASR_A3 volatile.Register32 // 0x028 (R/W) - MPU Alias 3 Region Attribute and Size Register
|
||||
}
|
||||
|
||||
var MPU = (*MPU_Type)(unsafe.Pointer(uintptr(0xe000ed90)))
|
||||
|
||||
type (
|
||||
RegionSize uint32
|
||||
AccessPerms uint32
|
||||
Extension uint32
|
||||
)
|
||||
|
||||
// MPU Control Register Definitions
|
||||
const (
|
||||
MPU_CTRL_PRIVDEFENA_Pos = 2 // MPU CTRL: PRIVDEFENA Position
|
||||
MPU_CTRL_PRIVDEFENA_Msk = 1 << MPU_CTRL_PRIVDEFENA_Pos // MPU CTRL: PRIVDEFENA Mask
|
||||
MPU_CTRL_HFNMIENA_Pos = 1 // MPU CTRL: HFNMIENA Position
|
||||
MPU_CTRL_HFNMIENA_Msk = 1 << MPU_CTRL_HFNMIENA_Pos // MPU CTRL: HFNMIENA Mask
|
||||
MPU_CTRL_ENABLE_Pos = 0 // MPU CTRL: ENABLE Position
|
||||
MPU_CTRL_ENABLE_Msk = 1 // MPU CTRL: ENABLE Mask
|
||||
)
|
||||
|
||||
// MPU Region Base Address Register Definitions
|
||||
const (
|
||||
MPU_RBAR_ADDR_Pos = 5 // MPU RBAR: ADDR Position
|
||||
MPU_RBAR_ADDR_Msk = 0x7FFFFFF << MPU_RBAR_ADDR_Pos // MPU RBAR: ADDR Mask
|
||||
MPU_RBAR_VALID_Pos = 4 // MPU RBAR: VALID Position
|
||||
MPU_RBAR_VALID_Msk = 1 << MPU_RBAR_VALID_Pos // MPU RBAR: VALID Mask
|
||||
MPU_RBAR_REGION_Pos = 0 // MPU RBAR: REGION Position
|
||||
MPU_RBAR_REGION_Msk = 0xF // MPU RBAR: REGION Mask
|
||||
)
|
||||
|
||||
// MPU Region Attribute and Size Register Definitions
|
||||
const (
|
||||
MPU_RASR_ATTRS_Pos = 16 // MPU RASR: MPU Region Attribute field Position
|
||||
MPU_RASR_ATTRS_Msk = 0xFFFF << MPU_RASR_ATTRS_Pos // MPU RASR: MPU Region Attribute field Mask
|
||||
MPU_RASR_XN_Pos = 28 // MPU RASR: ATTRS.XN Position
|
||||
MPU_RASR_XN_Msk = 1 << MPU_RASR_XN_Pos // MPU RASR: ATTRS.XN Mask
|
||||
MPU_RASR_AP_Pos = 24 // MPU RASR: ATTRS.AP Position
|
||||
MPU_RASR_AP_Msk = 0x7 << MPU_RASR_AP_Pos // MPU RASR: ATTRS.AP Mask
|
||||
MPU_RASR_TEX_Pos = 19 // MPU RASR: ATTRS.TEX Position
|
||||
MPU_RASR_TEX_Msk = 0x7 << MPU_RASR_TEX_Pos // MPU RASR: ATTRS.TEX Mask
|
||||
MPU_RASR_S_Pos = 18 // MPU RASR: ATTRS.S Position
|
||||
MPU_RASR_S_Msk = 1 << MPU_RASR_S_Pos // MPU RASR: ATTRS.S Mask
|
||||
MPU_RASR_C_Pos = 17 // MPU RASR: ATTRS.C Position
|
||||
MPU_RASR_C_Msk = 1 << MPU_RASR_C_Pos // MPU RASR: ATTRS.C Mask
|
||||
MPU_RASR_B_Pos = 16 // MPU RASR: ATTRS.B Position
|
||||
MPU_RASR_B_Msk = 1 << MPU_RASR_B_Pos // MPU RASR: ATTRS.B Mask
|
||||
MPU_RASR_SRD_Pos = 8 // MPU RASR: Sub-Region Disable Position
|
||||
MPU_RASR_SRD_Msk = 0xFF << MPU_RASR_SRD_Pos // MPU RASR: Sub-Region Disable Mask
|
||||
MPU_RASR_SIZE_Pos = 1 // MPU RASR: Region Size Field Position
|
||||
MPU_RASR_SIZE_Msk = 0x1F << MPU_RASR_SIZE_Pos // MPU RASR: Region Size Field Mask
|
||||
MPU_RASR_ENABLE_Pos = 0 // MPU RASR: Region enable bit Position
|
||||
MPU_RASR_ENABLE_Msk = 1 // MPU RASR: Region enable bit Disable Mask
|
||||
)
|
||||
|
||||
const (
|
||||
SCB_DCISW_WAY_Pos = 30 // SCB DCISW: Way Position
|
||||
SCB_DCISW_WAY_Msk = 3 << SCB_DCISW_WAY_Pos // SCB DCISW: Way Mask
|
||||
SCB_DCISW_SET_Pos = 5 // SCB DCISW: Set Position
|
||||
SCB_DCISW_SET_Msk = 0x1FF << SCB_DCISW_SET_Pos // SCB DCISW: Set Mask
|
||||
)
|
||||
|
||||
const (
|
||||
SCB_DCCISW_WAY_Pos = 30 // SCB DCCISW: Way Position
|
||||
SCB_DCCISW_WAY_Msk = 3 << SCB_DCCISW_WAY_Pos // SCB DCCISW: Way Mask
|
||||
SCB_DCCISW_SET_Pos = 5 // SCB DCCISW: Set Position
|
||||
SCB_DCCISW_SET_Msk = 0x1FF << SCB_DCCISW_SET_Pos // SCB DCCISW: Set Mask
|
||||
)
|
||||
|
||||
const (
|
||||
RGNSZ_32B RegionSize = 0x04 // MPU Region Size 32 Bytes
|
||||
RGNSZ_64B RegionSize = 0x05 // MPU Region Size 64 Bytes
|
||||
RGNSZ_128B RegionSize = 0x06 // MPU Region Size 128 Bytes
|
||||
RGNSZ_256B RegionSize = 0x07 // MPU Region Size 256 Bytes
|
||||
RGNSZ_512B RegionSize = 0x08 // MPU Region Size 512 Bytes
|
||||
RGNSZ_1KB RegionSize = 0x09 // MPU Region Size 1 KByte
|
||||
RGNSZ_2KB RegionSize = 0x0A // MPU Region Size 2 KBytes
|
||||
RGNSZ_4KB RegionSize = 0x0B // MPU Region Size 4 KBytes
|
||||
RGNSZ_8KB RegionSize = 0x0C // MPU Region Size 8 KBytes
|
||||
RGNSZ_16KB RegionSize = 0x0D // MPU Region Size 16 KBytes
|
||||
RGNSZ_32KB RegionSize = 0x0E // MPU Region Size 32 KBytes
|
||||
RGNSZ_64KB RegionSize = 0x0F // MPU Region Size 64 KBytes
|
||||
RGNSZ_128KB RegionSize = 0x10 // MPU Region Size 128 KBytes
|
||||
RGNSZ_256KB RegionSize = 0x11 // MPU Region Size 256 KBytes
|
||||
RGNSZ_512KB RegionSize = 0x12 // MPU Region Size 512 KBytes
|
||||
RGNSZ_1MB RegionSize = 0x13 // MPU Region Size 1 MByte
|
||||
RGNSZ_2MB RegionSize = 0x14 // MPU Region Size 2 MBytes
|
||||
RGNSZ_4MB RegionSize = 0x15 // MPU Region Size 4 MBytes
|
||||
RGNSZ_8MB RegionSize = 0x16 // MPU Region Size 8 MBytes
|
||||
RGNSZ_16MB RegionSize = 0x17 // MPU Region Size 16 MBytes
|
||||
RGNSZ_32MB RegionSize = 0x18 // MPU Region Size 32 MBytes
|
||||
RGNSZ_64MB RegionSize = 0x19 // MPU Region Size 64 MBytes
|
||||
RGNSZ_128MB RegionSize = 0x1A // MPU Region Size 128 MBytes
|
||||
RGNSZ_256MB RegionSize = 0x1B // MPU Region Size 256 MBytes
|
||||
RGNSZ_512MB RegionSize = 0x1C // MPU Region Size 512 MBytes
|
||||
RGNSZ_1GB RegionSize = 0x1D // MPU Region Size 1 GByte
|
||||
RGNSZ_2GB RegionSize = 0x1E // MPU Region Size 2 GBytes
|
||||
RGNSZ_4GB RegionSize = 0x1F // MPU Region Size 4 GBytes
|
||||
)
|
||||
|
||||
const (
|
||||
PERM_NONE AccessPerms = 0 // MPU Access Permission no access
|
||||
PERM_PRIV AccessPerms = 1 // MPU Access Permission privileged access only
|
||||
PERM_URO AccessPerms = 2 // MPU Access Permission unprivileged access read-only
|
||||
PERM_FULL AccessPerms = 3 // MPU Access Permission full access
|
||||
PERM_PRO AccessPerms = 5 // MPU Access Permission privileged access read-only
|
||||
PERM_RO AccessPerms = 6 // MPU Access Permission read-only access
|
||||
)
|
||||
|
||||
const (
|
||||
EXTN_NORMAL Extension = 0
|
||||
EXTN_DEVICE Extension = 2
|
||||
)
|
||||
|
||||
func (mpu *MPU_Type) Enable(enable bool) {
|
||||
if enable {
|
||||
mpu.CTRL.Set(MPU_CTRL_PRIVDEFENA_Msk | MPU_CTRL_ENABLE_Msk)
|
||||
SystemControl.SHCSR.SetBits(SCB_SHCSR_MEMFAULTENA_Msk)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
enableDcache(true)
|
||||
enableIcache(true)
|
||||
} else {
|
||||
enableIcache(false)
|
||||
enableDcache(false)
|
||||
arm.AsmFull(`
|
||||
dmb 0xF
|
||||
`, nil)
|
||||
SystemControl.SHCSR.ClearBits(SCB_SHCSR_MEMFAULTENA_Msk)
|
||||
mpu.CTRL.ClearBits(MPU_CTRL_ENABLE_Msk)
|
||||
}
|
||||
}
|
||||
|
||||
// MPU Region Base Address Register value
|
||||
func (mpu *MPU_Type) SetRBAR(region uint32, baseAddress uint32) {
|
||||
mpu.RBAR.Set((baseAddress & MPU_RBAR_ADDR_Msk) |
|
||||
(region & MPU_RBAR_REGION_Msk) | MPU_RBAR_VALID_Msk)
|
||||
}
|
||||
|
||||
// MPU Region Attribute and Size Register value
|
||||
func (mpu *MPU_Type) SetRASR(size RegionSize, access AccessPerms, ext Extension, exec, share, cache, buffer, disable bool) {
|
||||
boolBit := func(b bool) uint32 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
attr := ((uint32(ext) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) |
|
||||
((boolBit(share) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) |
|
||||
((boolBit(cache) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) |
|
||||
((boolBit(buffer) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk)
|
||||
mpu.RASR.Set(((boolBit(!exec) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) |
|
||||
((uint32(access) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) |
|
||||
(attr & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk)) |
|
||||
((boolBit(disable) << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) |
|
||||
((uint32(size) << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk) |
|
||||
MPU_RASR_ENABLE_Msk)
|
||||
}
|
||||
|
||||
func enableIcache(enable bool) {
|
||||
if enable != SystemControl.CCR.HasBits(SCB_CCR_IC_Msk) {
|
||||
if enable {
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
SystemControl.ICIALLU.Set(0)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
SystemControl.CCR.SetBits(SCB_CCR_IC_Msk)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
} else {
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
SystemControl.CCR.ClearBits(SCB_CCR_IC_Msk)
|
||||
SystemControl.ICIALLU.Set(0)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func enableDcache(enable bool) {
|
||||
if enable != SystemControl.CCR.HasBits(SCB_CCR_DC_Msk) {
|
||||
if enable {
|
||||
SystemControl.CSSELR.Set(0)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
`, nil)
|
||||
ccsidr := SystemControl.CCSIDR.Get()
|
||||
sets := (ccsidr & SCB_CCSIDR_NUMSETS_Msk) >> SCB_CCSIDR_NUMSETS_Pos
|
||||
for sets != 0 {
|
||||
ways := (ccsidr & SCB_CCSIDR_ASSOCIATIVITY_Msk) >> SCB_CCSIDR_ASSOCIATIVITY_Pos
|
||||
for ways != 0 {
|
||||
SystemControl.DCISW.Set(
|
||||
((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
|
||||
((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk))
|
||||
ways--
|
||||
}
|
||||
sets--
|
||||
}
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
`, nil)
|
||||
SystemControl.CCR.SetBits(SCB_CCR_DC_Msk)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
} else {
|
||||
var (
|
||||
ccsidr volatile.Register32
|
||||
sets volatile.Register32
|
||||
ways volatile.Register32
|
||||
)
|
||||
SystemControl.CSSELR.Set(0)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
`, nil)
|
||||
SystemControl.CCR.ClearBits(SCB_CCR_DC_Msk)
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
`, nil)
|
||||
ccsidr.Set(SystemControl.CCSIDR.Get())
|
||||
sets.Set((ccsidr.Get() & SCB_CCSIDR_NUMSETS_Msk) >> SCB_CCSIDR_NUMSETS_Pos)
|
||||
for sets.Get() != 0 {
|
||||
ways.Set((ccsidr.Get() & SCB_CCSIDR_ASSOCIATIVITY_Msk) >> SCB_CCSIDR_ASSOCIATIVITY_Pos)
|
||||
for ways.Get() != 0 {
|
||||
SystemControl.DCCISW.Set(
|
||||
((sets.Get() << SCB_DCCISW_SET_Pos) & SCB_DCCISW_SET_Msk) |
|
||||
((ways.Get() << SCB_DCCISW_WAY_Pos) & SCB_DCCISW_WAY_Msk))
|
||||
ways.Set(ways.Get() - 1)
|
||||
}
|
||||
sets.Set(sets.Get() - 1)
|
||||
}
|
||||
arm.AsmFull(`
|
||||
dsb 0xF
|
||||
isb 0xF
|
||||
`, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
#ifdef __riscv_flen
|
||||
#define NREG 48
|
||||
#define LFREG flw
|
||||
#define SFREG fsw
|
||||
#else
|
||||
#define NREG 16
|
||||
#endif
|
||||
|
||||
#if __riscv_xlen==64
|
||||
#define REGSIZE 8
|
||||
#define SREG sd
|
||||
#define LREG ld
|
||||
#else
|
||||
#define REGSIZE 4
|
||||
#define SREG sw
|
||||
#define LREG lw
|
||||
#endif
|
||||
|
||||
.section .text.handleInterruptASM
|
||||
.global handleInterruptASM
|
||||
.type handleInterruptASM,@function
|
||||
handleInterruptASM:
|
||||
// Save and restore all registers, because the hardware only saves/restores
|
||||
// the pc.
|
||||
// Note: we have to do this in assembly because the "interrupt"="machine"
|
||||
// attribute is broken in LLVM: https://bugs.llvm.org/show_bug.cgi?id=42984
|
||||
addi sp, sp, -NREG*REGSIZE
|
||||
SREG ra, 0*REGSIZE(sp)
|
||||
SREG t0, 1*REGSIZE(sp)
|
||||
SREG t1, 2*REGSIZE(sp)
|
||||
SREG t2, 3*REGSIZE(sp)
|
||||
SREG a0, 4*REGSIZE(sp)
|
||||
SREG a1, 5*REGSIZE(sp)
|
||||
SREG a2, 6*REGSIZE(sp)
|
||||
SREG a3, 7*REGSIZE(sp)
|
||||
SREG a4, 8*REGSIZE(sp)
|
||||
SREG a5, 9*REGSIZE(sp)
|
||||
SREG a6, 10*REGSIZE(sp)
|
||||
SREG a7, 11*REGSIZE(sp)
|
||||
SREG t3, 12*REGSIZE(sp)
|
||||
SREG t4, 13*REGSIZE(sp)
|
||||
SREG t5, 14*REGSIZE(sp)
|
||||
SREG t6, 15*REGSIZE(sp)
|
||||
#ifdef __riscv_flen
|
||||
SFREG f0, (0 + 16)*REGSIZE(sp)
|
||||
SFREG f1, (1 + 16)*REGSIZE(sp)
|
||||
SFREG f2, (2 + 16)*REGSIZE(sp)
|
||||
SFREG f3, (3 + 16)*REGSIZE(sp)
|
||||
SFREG f4, (4 + 16)*REGSIZE(sp)
|
||||
SFREG f5, (5 + 16)*REGSIZE(sp)
|
||||
SFREG f6, (6 + 16)*REGSIZE(sp)
|
||||
SFREG f7, (7 + 16)*REGSIZE(sp)
|
||||
SFREG f8, (8 + 16)*REGSIZE(sp)
|
||||
SFREG f9, (9 + 16)*REGSIZE(sp)
|
||||
SFREG f10,(10 + 16)*REGSIZE(sp)
|
||||
SFREG f11,(11 + 16)*REGSIZE(sp)
|
||||
SFREG f12,(12 + 16)*REGSIZE(sp)
|
||||
SFREG f13,(13 + 16)*REGSIZE(sp)
|
||||
SFREG f14,(14 + 16)*REGSIZE(sp)
|
||||
SFREG f15,(15 + 16)*REGSIZE(sp)
|
||||
SFREG f16,(16 + 16)*REGSIZE(sp)
|
||||
SFREG f17,(17 + 16)*REGSIZE(sp)
|
||||
SFREG f18,(18 + 16)*REGSIZE(sp)
|
||||
SFREG f19,(19 + 16)*REGSIZE(sp)
|
||||
SFREG f20,(20 + 16)*REGSIZE(sp)
|
||||
SFREG f21,(21 + 16)*REGSIZE(sp)
|
||||
SFREG f22,(22 + 16)*REGSIZE(sp)
|
||||
SFREG f23,(23 + 16)*REGSIZE(sp)
|
||||
SFREG f24,(24 + 16)*REGSIZE(sp)
|
||||
SFREG f25,(25 + 16)*REGSIZE(sp)
|
||||
SFREG f26,(26 + 16)*REGSIZE(sp)
|
||||
SFREG f27,(27 + 16)*REGSIZE(sp)
|
||||
SFREG f28,(28 + 16)*REGSIZE(sp)
|
||||
SFREG f29,(29 + 16)*REGSIZE(sp)
|
||||
SFREG f30,(30 + 16)*REGSIZE(sp)
|
||||
SFREG f31,(31 + 16)*REGSIZE(sp)
|
||||
#endif
|
||||
call handleInterrupt
|
||||
#ifdef __riscv_flen
|
||||
LFREG f0, (31 + 16)*REGSIZE(sp)
|
||||
LFREG f1, (30 + 16)*REGSIZE(sp)
|
||||
LFREG f2, (29 + 16)*REGSIZE(sp)
|
||||
LFREG f3, (28 + 16)*REGSIZE(sp)
|
||||
LFREG f4, (27 + 16)*REGSIZE(sp)
|
||||
LFREG f5, (26 + 16)*REGSIZE(sp)
|
||||
LFREG f6, (25 + 16)*REGSIZE(sp)
|
||||
LFREG f7, (24 + 16)*REGSIZE(sp)
|
||||
LFREG f8, (23 + 16)*REGSIZE(sp)
|
||||
LFREG f9, (22 + 16)*REGSIZE(sp)
|
||||
LFREG f10,(21 + 16)*REGSIZE(sp)
|
||||
LFREG f11,(20 + 16)*REGSIZE(sp)
|
||||
LFREG f12,(19 + 16)*REGSIZE(sp)
|
||||
LFREG f13,(18 + 16)*REGSIZE(sp)
|
||||
LFREG f14,(17 + 16)*REGSIZE(sp)
|
||||
LFREG f15,(16 + 16)*REGSIZE(sp)
|
||||
LFREG f16,(15 + 16)*REGSIZE(sp)
|
||||
LFREG f17,(14 + 16)*REGSIZE(sp)
|
||||
LFREG f18,(13 + 16)*REGSIZE(sp)
|
||||
LFREG f19,(12 + 16)*REGSIZE(sp)
|
||||
LFREG f20,(11 + 16)*REGSIZE(sp)
|
||||
LFREG f21,(10 + 16)*REGSIZE(sp)
|
||||
LFREG f22,(9 + 16)*REGSIZE(sp)
|
||||
LFREG f23,(8 + 16)*REGSIZE(sp)
|
||||
LFREG f24,(7 + 16)*REGSIZE(sp)
|
||||
LFREG f25,(6 + 16)*REGSIZE(sp)
|
||||
LFREG f26,(5 + 16)*REGSIZE(sp)
|
||||
LFREG f27,(4 + 16)*REGSIZE(sp)
|
||||
LFREG f28,(3 + 16)*REGSIZE(sp)
|
||||
LFREG f29,(2 + 16)*REGSIZE(sp)
|
||||
LFREG f30,(1 + 16)*REGSIZE(sp)
|
||||
LFREG f31,(0 + 16)*REGSIZE(sp)
|
||||
#endif
|
||||
LREG t6, 15*REGSIZE(sp)
|
||||
LREG t5, 14*REGSIZE(sp)
|
||||
LREG t4, 13*REGSIZE(sp)
|
||||
LREG t3, 12*REGSIZE(sp)
|
||||
LREG a7, 11*REGSIZE(sp)
|
||||
LREG a6, 10*REGSIZE(sp)
|
||||
LREG a5, 9*REGSIZE(sp)
|
||||
LREG a4, 8*REGSIZE(sp)
|
||||
LREG a3, 7*REGSIZE(sp)
|
||||
LREG a2, 6*REGSIZE(sp)
|
||||
LREG a1, 5*REGSIZE(sp)
|
||||
LREG a0, 4*REGSIZE(sp)
|
||||
LREG t2, 3*REGSIZE(sp)
|
||||
LREG t1, 2*REGSIZE(sp)
|
||||
LREG t0, 1*REGSIZE(sp)
|
||||
LREG ra, 0*REGSIZE(sp)
|
||||
addi sp, sp, NREG*REGSIZE
|
||||
mret
|
||||
@@ -19,19 +19,3 @@ func Asm(asm string)
|
||||
// You can use {} in the asm string (which expands to a register) to set the
|
||||
// return value.
|
||||
func AsmFull(asm string, regs map[string]interface{}) uintptr
|
||||
|
||||
// DisableInterrupts disables all interrupts, and returns the old interrupt
|
||||
// state.
|
||||
func DisableInterrupts() uintptr {
|
||||
// Note: this can be optimized with a CSRRW instruction, which atomically
|
||||
// swaps the value and returns the old value.
|
||||
mask := MIE.Get()
|
||||
MIE.Set(0)
|
||||
return mask
|
||||
}
|
||||
|
||||
// EnableInterrupts enables all interrupts again. The value passed in must be
|
||||
// the mask returned by DisableInterrupts.
|
||||
func EnableInterrupts(mask uintptr) {
|
||||
MIE.Set(mask)
|
||||
}
|
||||
|
||||
@@ -9,12 +9,52 @@ _start:
|
||||
// Load the globals pointer. The program will load pointers relative to this
|
||||
// register, so it must be set to the right value on startup.
|
||||
// See: https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/#the-gp-global-pointer-register
|
||||
// Linker relaxations must be disabled to avoid the initialization beign
|
||||
// relaxed with an uninitialized global pointer: mv gp, gp
|
||||
.option push
|
||||
.option norelax
|
||||
la gp, __global_pointer$
|
||||
.option pop
|
||||
|
||||
// Jump to runtime.main
|
||||
call main
|
||||
|
||||
.section .text.handleInterruptASM
|
||||
.global handleInterruptASM
|
||||
.type handleInterruptASM,@function
|
||||
handleInterruptASM:
|
||||
// Save and restore all registers, because the hardware only saves/restores
|
||||
// the pc.
|
||||
// Note: we have to do this in assembly because the "interrupt"="machine"
|
||||
// attribute is broken in LLVM: https://bugs.llvm.org/show_bug.cgi?id=42984
|
||||
addi sp, sp, -64
|
||||
sw ra, 60(sp)
|
||||
sw t0, 56(sp)
|
||||
sw t1, 52(sp)
|
||||
sw t2, 48(sp)
|
||||
sw a0, 44(sp)
|
||||
sw a1, 40(sp)
|
||||
sw a2, 36(sp)
|
||||
sw a3, 32(sp)
|
||||
sw a4, 28(sp)
|
||||
sw a5, 24(sp)
|
||||
sw a6, 20(sp)
|
||||
sw a7, 16(sp)
|
||||
sw t3, 12(sp)
|
||||
sw t4, 8(sp)
|
||||
sw t5, 4(sp)
|
||||
sw t6, 0(sp)
|
||||
call handleInterrupt
|
||||
lw t6, 0(sp)
|
||||
lw t5, 4(sp)
|
||||
lw t4, 8(sp)
|
||||
lw t3, 12(sp)
|
||||
lw a7, 16(sp)
|
||||
lw a6, 20(sp)
|
||||
lw a5, 24(sp)
|
||||
lw a4, 28(sp)
|
||||
lw a3, 32(sp)
|
||||
lw a2, 36(sp)
|
||||
lw a1, 40(sp)
|
||||
lw a0, 44(sp)
|
||||
lw t2, 48(sp)
|
||||
lw t1, 52(sp)
|
||||
lw t0, 56(sp)
|
||||
lw ra, 60(sp)
|
||||
addi sp, sp, 64
|
||||
mret
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
// Hand created file. DO NOT DELETE.
|
||||
// atsamd51x bitfield definitions that are not auto-generated by gen-device-svd.go
|
||||
|
||||
// +build sam,atsamd51
|
||||
|
||||
// These are the supported pchctrl function numberings on the atsamd51x
|
||||
// See http://ww1.microchip.com/downloads/en/DeviceDoc/SAM_D5xE5x_Family_Data_Sheet_DS60001507F.pdf
|
||||
// table 14-9
|
||||
|
||||
package sam
|
||||
|
||||
const (
|
||||
PCHCTRL_GCLK_OSCCTRL_DFLL48 = 0 // DFLL48 input clock source
|
||||
PCHCTRL_GCLK_OSCCTRL_FDPLL0 = 1 // Reference clock for FDPLL0
|
||||
PCHCTRL_GCLK_OSCCTRL_FDPLL1 = 2 // Reference clock for FDPLL1
|
||||
PCHCTRL_GCLK_OSCCTRL_FDPLL0_32K = 3 // FDPLL0 = 3 // 32KHz clock for internal lock timer
|
||||
PCHCTRL_GCLK_OSCCTRL_FDPLL1_32K = 3 // FDPLL1 = 3 // 32KHz clock for internal lock timer
|
||||
PCHCTRL_GCLK_SDHC0_SLOW = 3 // SDHC0 = 3 // Slow
|
||||
PCHCTRL_GCLK_SDHC1_SLOW = 3 // SDHC1 = 3 // Slow
|
||||
PCHCTRL_GCLK_SERCOMX_SLOW = 3 // GCLK_SERCOM[0..7]_SLOW = 3
|
||||
PCHCTRL_GCLK_EIC = 4
|
||||
PCHCTRL_GCLK_FREQM_MSR = 5 // FREQM Measure
|
||||
PCHCTRL_GCLK_FREQM_REF = 6 // FREQM Reference
|
||||
PCHCTRL_GCLK_SERCOM0_CORE = 7 // SERCOM0 Core
|
||||
PCHCTRL_GCLK_SERCOM1_CORE = 8 // SERCOM1 Core
|
||||
PCHCTRL_GCLK_TC0 = 9
|
||||
PCHCTRL_GCLK_TC1 = 9 // TC0, TC1
|
||||
PCHCTRL_GCLK_USB = 10 // USB
|
||||
PCHCTRL_GCLK_EVSYS0 = 11
|
||||
PCHCTRL_GCLK_EVSYS1 = 12
|
||||
PCHCTRL_GCLK_EVSYS2 = 13
|
||||
PCHCTRL_GCLK_EVSYS3 = 14
|
||||
PCHCTRL_GCLK_EVSYS4 = 15
|
||||
PCHCTRL_GCLK_EVSYS5 = 16
|
||||
PCHCTRL_GCLK_EVSYS6 = 17
|
||||
PCHCTRL_GCLK_EVSYS7 = 18
|
||||
PCHCTRL_GCLK_EVSYS8 = 19
|
||||
PCHCTRL_GCLK_EVSYS9 = 20
|
||||
PCHCTRL_GCLK_EVSYS10 = 21
|
||||
PCHCTRL_GCLK_EVSYS11 = 22
|
||||
PCHCTRL_GCLK_SERCOM2_CORE = 23 // SERCOM2 Core
|
||||
PCHCTRL_GCLK_SERCOM3_CORE = 24 // SERCOM3 Core
|
||||
PCHCTRL_GCLK_TCC0 = 25
|
||||
PCHCTRL_GCLK_TCC1 = 25 // TCC0, TCC1
|
||||
PCHCTRL_GCLK_TC2 = 26
|
||||
PCHCTRL_GCLK_TC3 = 26 // TC2, TC3
|
||||
PCHCTRL_GCLK_CAN0 = 27 // CAN0
|
||||
PCHCTRL_GCLK_CAN1 = 28 // CAN1
|
||||
PCHCTRL_GCLK_TCC2 = 29
|
||||
PCHCTRL_GCLK_TCC3 = 29 // TCC2, TCC3
|
||||
PCHCTRL_GCLK_TC4 = 30
|
||||
PCHCTRL_GCLK_TC5 = 30 // TC4, TC5
|
||||
PCHCTRL_GCLK_PDEC = 31 // PDEC
|
||||
PCHCTRL_GCLK_AC = 32 // AC
|
||||
PCHCTRL_GCLK_CCL = 33 // CCL
|
||||
PCHCTRL_GCLK_SERCOM4_CORE = 34 // SERCOM4 Core
|
||||
PCHCTRL_GCLK_SERCOM5_CORE = 35 // SERCOM5 Core
|
||||
PCHCTRL_GCLK_SERCOM6_CORE = 36 // SERCOM6 Core
|
||||
PCHCTRL_GCLK_SERCOM7_CORE = 37 // SERCOM7 Core
|
||||
PCHCTRL_GCLK_TCC4 = 38 // TCC4
|
||||
PCHCTRL_GCLK_TC6 = 39
|
||||
PCHCTRL_GCLK_TC7 = 39 // TC6, TC7
|
||||
PCHCTRL_GCLK_ADC0 = 40 // ADC0
|
||||
PCHCTRL_GCLK_ADC1 = 41 // ADC1
|
||||
PCHCTRL_GCLK_DAC = 42 // DAC
|
||||
PCHCTRL_GCLK_I2S0 = 43
|
||||
PCHCTRL_GCLK_I2S1 = 44
|
||||
PCHCTRL_GCLK_SDHC0 = 45 // SDHC0
|
||||
PCHCTRL_GCLK_SDHC1 = 46 // SDHC1
|
||||
PCHCTRL_GCLK_CM4_TRACE = 47 // CM4 Trace
|
||||
)
|
||||
+3
-5
@@ -1,9 +1,7 @@
|
||||
// Hand created file. DO NOT DELETE.
|
||||
// STM32FXXX (except stm32f1xx) bitfield definitions that are not
|
||||
// auto-generated by gen-device-svd.go
|
||||
// +build stm32f4
|
||||
// These are the supported alternate function numberings on the stm32f407
|
||||
// +build stm32,stm32f407
|
||||
|
||||
// Alternate function settings on the stm32f4 series
|
||||
// Alternate function settings on the stm32f4xx series
|
||||
|
||||
package stm32
|
||||
|
||||
@@ -5,14 +5,16 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// This example assumes that the button is connected to pin 8. Change the value
|
||||
// below to use a different pin.
|
||||
const (
|
||||
led = machine.LED
|
||||
button = machine.BUTTON
|
||||
button = machine.Pin(8)
|
||||
)
|
||||
|
||||
func main() {
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||
button.Configure(machine.PinConfig{Mode: machine.PinInput})
|
||||
|
||||
for {
|
||||
if button.Get() {
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
// +build circuitplay_express
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
)
|
||||
|
||||
func init() {
|
||||
enable := machine.PA30
|
||||
enable.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
enable.Set(true)
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
// Simplistic example using the DAC on the Circuit Playground Express.
|
||||
//
|
||||
// To actually use the DAC for producing complex waveforms or samples requires a DMA
|
||||
// timer-based playback mechanism which is beyond the scope of this example.
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
speaker := machine.A0
|
||||
speaker.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
machine.DAC0.Configure(machine.DACConfig{})
|
||||
|
||||
data := []uint16{0xFFFF, 0x8000, 0x4000, 0x2000, 0x1000, 0x0000}
|
||||
|
||||
for {
|
||||
for _, val := range data {
|
||||
play(val)
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func play(val uint16) {
|
||||
for i := 0; i < 100; i++ {
|
||||
machine.DAC0.Set(val)
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
|
||||
machine.DAC0.Set(0)
|
||||
time.Sleep(2 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
// +build pyportal
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"machine"
|
||||
)
|
||||
|
||||
func init() {
|
||||
enable := machine.SPK_SD
|
||||
enable.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
enable.Set(true)
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// +build circuitplay_express
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
buttonMode = machine.PinInputPulldown
|
||||
buttonPinChange = machine.PinFalling
|
||||
)
|
||||
@@ -1,10 +0,0 @@
|
||||
// +build pca10040
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
buttonMode = machine.PinInputPullup
|
||||
buttonPinChange = machine.PinRising
|
||||
)
|
||||
@@ -1,52 +0,0 @@
|
||||
package main
|
||||
|
||||
// This example demonstrates how to use pin change interrupts.
|
||||
//
|
||||
// This is only an example and should not be copied directly in any serious
|
||||
// circuit, because it lacks an important feature: debouncing.
|
||||
// See: https://en.wikipedia.org/wiki/Switch#Contact_bounce
|
||||
|
||||
import (
|
||||
"machine"
|
||||
"runtime/volatile"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
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).
|
||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
led.Low()
|
||||
|
||||
// Make sure the pin is configured as a pullup to avoid floating inputs.
|
||||
// Pullup works for most buttons, as most buttons short to ground when
|
||||
// pressed.
|
||||
button.Configure(machine.PinConfig{Mode: buttonMode})
|
||||
|
||||
// Set an interrupt on this pin.
|
||||
err := button.SetInterrupt(buttonPinChange, func(machine.Pin) {
|
||||
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())
|
||||
}
|
||||
|
||||
// Make sure the program won't exit.
|
||||
for {
|
||||
time.Sleep(time.Hour)
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// +build wioterminal
|
||||
|
||||
package main
|
||||
|
||||
import "machine"
|
||||
|
||||
const (
|
||||
buttonMode = machine.PinInput
|
||||
buttonPinChange = machine.PinFalling
|
||||
)
|
||||
+6
-16
@@ -8,9 +8,9 @@ import (
|
||||
// This example assumes that an RGB LED is connected to pins 3, 5 and 6 on an Arduino.
|
||||
// Change the values below to use different pins.
|
||||
const (
|
||||
redPin = machine.D4
|
||||
greenPin = machine.D5
|
||||
bluePin = machine.D6
|
||||
redPin = 3
|
||||
greenPin = 5
|
||||
bluePin = 6
|
||||
)
|
||||
|
||||
// cycleColor is just a placeholder until math/rand or some equivalent is working.
|
||||
@@ -28,16 +28,13 @@ func main() {
|
||||
machine.InitPWM()
|
||||
|
||||
red := machine.PWM{redPin}
|
||||
err := red.Configure()
|
||||
checkError(err, "failed to configure red pin")
|
||||
red.Configure()
|
||||
|
||||
green := machine.PWM{greenPin}
|
||||
err = green.Configure()
|
||||
checkError(err, "failed to configure green pin")
|
||||
green.Configure()
|
||||
|
||||
blue := machine.PWM{bluePin}
|
||||
err = blue.Configure()
|
||||
checkError(err, "failed to configure blue pin")
|
||||
blue.Configure()
|
||||
|
||||
var rc uint8
|
||||
var gc uint8 = 20
|
||||
@@ -55,10 +52,3 @@ func main() {
|
||||
time.Sleep(time.Millisecond * 500)
|
||||
}
|
||||
}
|
||||
|
||||
func checkError(err error, msg string) {
|
||||
if err != nil {
|
||||
print(msg, ": ", err.Error())
|
||||
println()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@ import (
|
||||
"machine"
|
||||
)
|
||||
|
||||
var timerCh = make(chan struct{}, 1)
|
||||
|
||||
func main() {
|
||||
machine.LED.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||
|
||||
@@ -14,18 +12,17 @@ func main() {
|
||||
arm.SetupSystemTimer(machine.CPUFrequency() / 10)
|
||||
|
||||
for {
|
||||
machine.LED.Low()
|
||||
<-timerCh
|
||||
machine.LED.High()
|
||||
<-timerCh
|
||||
}
|
||||
}
|
||||
|
||||
var led_state bool
|
||||
|
||||
//export SysTick_Handler
|
||||
func timer_isr() {
|
||||
select {
|
||||
case timerCh <- struct{}{}:
|
||||
default:
|
||||
// The consumer is running behind.
|
||||
if led_state {
|
||||
machine.LED.Low()
|
||||
} else {
|
||||
machine.LED.High()
|
||||
}
|
||||
led_state = !led_state
|
||||
}
|
||||
|
||||
@@ -1,253 +0,0 @@
|
||||
package bytealg
|
||||
|
||||
const (
|
||||
// Index can search any valid length of string.
|
||||
|
||||
MaxLen = int(-1) >> 31
|
||||
MaxBruteForce = MaxLen
|
||||
)
|
||||
|
||||
// Compare two byte slices.
|
||||
// Returns -1 if the first differing byte is lower in a, or 1 if the first differing byte is greater in b.
|
||||
// If the byte slices are equal, returns 0.
|
||||
// If the lengths are different and there are no differing bytes, compares based on length.
|
||||
func Compare(a, b []byte) int {
|
||||
// Compare for differing bytes.
|
||||
for i := 0; i < len(a) && i < len(b); i++ {
|
||||
switch {
|
||||
case a[0] < b[0]:
|
||||
return -1
|
||||
case a[0] > b[0]:
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Compare lengths.
|
||||
switch {
|
||||
case len(a) > len(b):
|
||||
return 1
|
||||
case len(a) < len(b):
|
||||
return -1
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
// Count the number of instances of a byte in a slice.
|
||||
func Count(b []byte, c byte) int {
|
||||
// Use a simple implementation, as there is no intrinsic that does this like we want.
|
||||
n := 0
|
||||
for _, v := range b {
|
||||
if v == c {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Count the number of instances of a byte in a string.
|
||||
func CountString(s string, c byte) int {
|
||||
// Use a simple implementation, as there is no intrinsic that does this like we want.
|
||||
// Currently, the compiler does not generate zero-copy byte-string conversions, so this needs to be seperate from Count.
|
||||
n := 0
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == c {
|
||||
n++
|
||||
}
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// Cutover is not reachable in TinyGo, but must exist as it is referenced.
|
||||
func Cutover(n int) int {
|
||||
// Setting MaxLen and MaxBruteForce should force a different path to be taken.
|
||||
// This should never be called.
|
||||
panic("cutover is unreachable")
|
||||
}
|
||||
|
||||
// Equal checks if two byte slices are equal.
|
||||
// It is equivalent to bytes.Equal.
|
||||
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
|
||||
}
|
||||
|
||||
// Index finds the base index of the first instance of the byte sequence b in a.
|
||||
// If a does not contain b, this returns -1.
|
||||
func Index(a, b []byte) int {
|
||||
for i := 0; i <= len(a)-len(b); i++ {
|
||||
if Equal(a[i:i+len(b)], b) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Index finds the index of the first instance of the specified byte in the slice.
|
||||
// If the byte is not found, this returns -1.
|
||||
func IndexByte(b []byte, c byte) int {
|
||||
for i, v := range b {
|
||||
if v == c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Index finds the index of the first instance of the specified byte in the string.
|
||||
// If the byte is not found, this returns -1.
|
||||
func IndexByteString(s string, c byte) int {
|
||||
for i := 0; i < len(s); i++ {
|
||||
if s[i] == c {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Index finds the base index of the first instance of a substring in a string.
|
||||
// If the substring is not found, this returns -1.
|
||||
func IndexString(str, sub string) int {
|
||||
for i := 0; i <= len(str)-len(sub); i++ {
|
||||
if str[i:i+len(sub)] == sub {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// The following code has been copied from the Go 1.15 release tree.
|
||||
|
||||
// PrimeRK is the prime base used in Rabin-Karp algorithm.
|
||||
const PrimeRK = 16777619
|
||||
|
||||
// HashStrBytes returns the hash and the appropriate multiplicative
|
||||
// factor for use in Rabin-Karp algorithm.
|
||||
func HashStrBytes(sep []byte) (uint32, uint32) {
|
||||
hash := uint32(0)
|
||||
for i := 0; i < len(sep); i++ {
|
||||
hash = hash*PrimeRK + uint32(sep[i])
|
||||
}
|
||||
var pow, sq uint32 = 1, PrimeRK
|
||||
for i := len(sep); i > 0; i >>= 1 {
|
||||
if i&1 != 0 {
|
||||
pow *= sq
|
||||
}
|
||||
sq *= sq
|
||||
}
|
||||
return hash, pow
|
||||
}
|
||||
|
||||
// HashStr returns the hash and the appropriate multiplicative
|
||||
// factor for use in Rabin-Karp algorithm.
|
||||
func HashStr(sep string) (uint32, uint32) {
|
||||
hash := uint32(0)
|
||||
for i := 0; i < len(sep); i++ {
|
||||
hash = hash*PrimeRK + uint32(sep[i])
|
||||
}
|
||||
var pow, sq uint32 = 1, PrimeRK
|
||||
for i := len(sep); i > 0; i >>= 1 {
|
||||
if i&1 != 0 {
|
||||
pow *= sq
|
||||
}
|
||||
sq *= sq
|
||||
}
|
||||
return hash, pow
|
||||
}
|
||||
|
||||
// HashStrRevBytes returns the hash of the reverse of sep and the
|
||||
// appropriate multiplicative factor for use in Rabin-Karp algorithm.
|
||||
func HashStrRevBytes(sep []byte) (uint32, uint32) {
|
||||
hash := uint32(0)
|
||||
for i := len(sep) - 1; i >= 0; i-- {
|
||||
hash = hash*PrimeRK + uint32(sep[i])
|
||||
}
|
||||
var pow, sq uint32 = 1, PrimeRK
|
||||
for i := len(sep); i > 0; i >>= 1 {
|
||||
if i&1 != 0 {
|
||||
pow *= sq
|
||||
}
|
||||
sq *= sq
|
||||
}
|
||||
return hash, pow
|
||||
}
|
||||
|
||||
// HashStrRev returns the hash of the reverse of sep and the
|
||||
// appropriate multiplicative factor for use in Rabin-Karp algorithm.
|
||||
func HashStrRev(sep string) (uint32, uint32) {
|
||||
hash := uint32(0)
|
||||
for i := len(sep) - 1; i >= 0; i-- {
|
||||
hash = hash*PrimeRK + uint32(sep[i])
|
||||
}
|
||||
var pow, sq uint32 = 1, PrimeRK
|
||||
for i := len(sep); i > 0; i >>= 1 {
|
||||
if i&1 != 0 {
|
||||
pow *= sq
|
||||
}
|
||||
sq *= sq
|
||||
}
|
||||
return hash, pow
|
||||
}
|
||||
|
||||
// IndexRabinKarpBytes uses the Rabin-Karp search algorithm to return the index of the
|
||||
// first occurence of substr in s, or -1 if not present.
|
||||
func IndexRabinKarpBytes(s, sep []byte) int {
|
||||
// Rabin-Karp search
|
||||
hashsep, pow := HashStrBytes(sep)
|
||||
n := len(sep)
|
||||
var h uint32
|
||||
for i := 0; i < n; i++ {
|
||||
h = h*PrimeRK + uint32(s[i])
|
||||
}
|
||||
if h == hashsep && Equal(s[:n], sep) {
|
||||
return 0
|
||||
}
|
||||
for i := n; i < len(s); {
|
||||
h *= PrimeRK
|
||||
h += uint32(s[i])
|
||||
h -= pow * uint32(s[i-n])
|
||||
i++
|
||||
if h == hashsep && Equal(s[i-n:i], sep) {
|
||||
return i - n
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// IndexRabinKarp uses the Rabin-Karp search algorithm to return the index of the
|
||||
// first occurence of substr in s, or -1 if not present.
|
||||
func IndexRabinKarp(s, substr string) int {
|
||||
// Rabin-Karp search
|
||||
hashss, pow := HashStr(substr)
|
||||
n := len(substr)
|
||||
var h uint32
|
||||
for i := 0; i < n; i++ {
|
||||
h = h*PrimeRK + uint32(s[i])
|
||||
}
|
||||
if h == hashss && s[:n] == substr {
|
||||
return 0
|
||||
}
|
||||
for i := n; i < len(s); {
|
||||
h *= PrimeRK
|
||||
h += uint32(s[i])
|
||||
h -= pow * uint32(s[i-n])
|
||||
i++
|
||||
if h == hashss && s[i-n:i] == substr {
|
||||
return i - n
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package task
|
||||
|
||||
import "runtime/interrupt"
|
||||
|
||||
const asserts = false
|
||||
|
||||
// Queue is a FIFO container of tasks.
|
||||
@@ -12,9 +10,7 @@ type Queue struct {
|
||||
|
||||
// Push a task onto the queue.
|
||||
func (q *Queue) Push(t *Task) {
|
||||
i := interrupt.Disable()
|
||||
if asserts && t.Next != nil {
|
||||
interrupt.Restore(i)
|
||||
panic("runtime: pushing a task to a queue with a non-nil Next pointer")
|
||||
}
|
||||
if q.tail != nil {
|
||||
@@ -25,15 +21,12 @@ func (q *Queue) Push(t *Task) {
|
||||
if q.head == nil {
|
||||
q.head = t
|
||||
}
|
||||
interrupt.Restore(i)
|
||||
}
|
||||
|
||||
// Pop a task off of the queue.
|
||||
func (q *Queue) Pop() *Task {
|
||||
i := interrupt.Disable()
|
||||
t := q.head
|
||||
if t == nil {
|
||||
interrupt.Restore(i)
|
||||
return nil
|
||||
}
|
||||
q.head = t.Next
|
||||
@@ -41,13 +34,11 @@ func (q *Queue) Pop() *Task {
|
||||
q.tail = nil
|
||||
}
|
||||
t.Next = nil
|
||||
interrupt.Restore(i)
|
||||
return t
|
||||
}
|
||||
|
||||
// Append pops the contents of another queue and pushes them onto the end of this queue.
|
||||
func (q *Queue) Append(other *Queue) {
|
||||
i := interrupt.Disable()
|
||||
if q.head == nil {
|
||||
q.head = other.head
|
||||
} else {
|
||||
@@ -55,15 +46,6 @@ func (q *Queue) Append(other *Queue) {
|
||||
}
|
||||
q.tail = other.tail
|
||||
other.head, other.tail = nil, nil
|
||||
interrupt.Restore(i)
|
||||
}
|
||||
|
||||
// Empty checks if the queue is empty.
|
||||
func (q *Queue) Empty() bool {
|
||||
i := interrupt.Disable()
|
||||
empty := q.head == nil
|
||||
interrupt.Restore(i)
|
||||
return empty
|
||||
}
|
||||
|
||||
// Stack is a LIFO container of tasks.
|
||||
@@ -75,24 +57,19 @@ type Stack struct {
|
||||
|
||||
// Push a task onto the stack.
|
||||
func (s *Stack) Push(t *Task) {
|
||||
i := interrupt.Disable()
|
||||
if asserts && t.Next != nil {
|
||||
interrupt.Restore(i)
|
||||
panic("runtime: pushing a task to a stack with a non-nil Next pointer")
|
||||
}
|
||||
s.top, t.Next = t, s.top
|
||||
interrupt.Restore(i)
|
||||
}
|
||||
|
||||
// Pop a task off of the stack.
|
||||
func (s *Stack) Pop() *Task {
|
||||
i := interrupt.Disable()
|
||||
t := s.top
|
||||
if t != nil {
|
||||
s.top = t.Next
|
||||
t.Next = nil
|
||||
}
|
||||
interrupt.Restore(i)
|
||||
t.Next = nil
|
||||
return t
|
||||
}
|
||||
|
||||
@@ -112,13 +89,10 @@ func (t *Task) tail() *Task {
|
||||
// Queue moves the contents of the stack into a queue.
|
||||
// Elements can be popped from the queue in the same order that they would be popped from the stack.
|
||||
func (s *Stack) Queue() Queue {
|
||||
i := interrupt.Disable()
|
||||
head := s.top
|
||||
s.top = nil
|
||||
q := Queue{
|
||||
return Queue{
|
||||
head: head,
|
||||
tail: head.tail(),
|
||||
}
|
||||
interrupt.Restore(i)
|
||||
return q
|
||||
}
|
||||
|
||||
@@ -18,8 +18,3 @@ type Task struct {
|
||||
// state is the underlying running state of the task.
|
||||
state state
|
||||
}
|
||||
|
||||
// getGoroutineStackSize is a compiler intrinsic that returns the stack size for
|
||||
// the given function and falls back to the default stack size. It is replaced
|
||||
// with a load from a special section just before codegen.
|
||||
func getGoroutineStackSize(fn uintptr) uintptr
|
||||
|
||||
@@ -67,7 +67,7 @@ func createTask() *Task {
|
||||
// start invokes a function in a new goroutine. Calls to this are inserted by the compiler.
|
||||
// The created goroutine starts running immediately.
|
||||
// This is implemented inside the compiler.
|
||||
func start(fn uintptr, args unsafe.Pointer, stackSize uintptr)
|
||||
func start(fn uintptr, args unsafe.Pointer)
|
||||
|
||||
// Current returns the current active task.
|
||||
// This is implemented inside the compiler.
|
||||
@@ -85,14 +85,9 @@ type taskHolder interface {
|
||||
getReturnPtr() unsafe.Pointer
|
||||
}
|
||||
|
||||
// If there are no direct references to the task methods, they will not be discovered by the compiler, and this will trigger a compiler error.
|
||||
// Instantiating this interface forces discovery of these methods.
|
||||
var _ = taskHolder((*Task)(nil))
|
||||
|
||||
func fake() {
|
||||
// Hack to ensure intrinsics are discovered.
|
||||
Current()
|
||||
go func() {}()
|
||||
Pause()
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ func Current() *Task {
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
|
||||
func start(fn uintptr, args unsafe.Pointer) {
|
||||
// The compiler will error if this is reachable.
|
||||
runtimePanic("scheduler is disabled")
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user