mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-03 02:27:48 +00:00
Compare commits
87 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ce0abac5a3 | |||
| 43d7f48de4 | |||
| f7f2082979 | |||
| 9b1a19f184 | |||
| 1ad6953858 | |||
| 3e8cdb62c9 | |||
| 720a54a0fe | |||
| de45da5df4 | |||
| c9fc95f6f3 | |||
| 2721ab146f | |||
| 81c723db1a | |||
| 9a20af5b59 | |||
| 4e8e3f348f | |||
| 496452b676 | |||
| e86ca2080d | |||
| e2bf7bbb49 | |||
| 4d1d0c2d3b | |||
| 2281b6a3f5 | |||
| 4321923641 | |||
| 4e4b5955db | |||
| 169d5f17b8 | |||
| 9ed5eae6a9 | |||
| e2c55e3d26 | |||
| d3f5b51cd8 | |||
| 2396c22658 | |||
| d61d5d7ab1 | |||
| c5a896771d | |||
| 0c880ec44c | |||
| 64d51b215f | |||
| f103e910d7 | |||
| 40afeea569 | |||
| 97122972fb | |||
| 72064e12db | |||
| 3c31a3110f | |||
| 0e73790d67 | |||
| bcbc241d81 | |||
| 5e2a8024a3 | |||
| b92fad8da6 | |||
| 5c8d4e54d6 | |||
| fed433c046 | |||
| 734613c20e | |||
| 1570adac1c | |||
| c72f9eb08c | |||
| 19c7965fc5 | |||
| c248418dbe | |||
| 4ca2d3f0cf | |||
| 35015a7918 | |||
| bde73fc214 | |||
| ab2a81cc52 | |||
| 2a98433c8e | |||
| 4918395f88 | |||
| 67ac4fdd8e | |||
| e69131c0d3 | |||
| 9f4459cee1 | |||
| 3c55689566 | |||
| 95f509b109 | |||
| dda576e80b | |||
| da505a6b17 | |||
| 424d775bf4 | |||
| 726d735ad3 | |||
| b9fd6cee6f | |||
| 76fb3bd177 | |||
| 29ca1147f5 | |||
| 473644d918 | |||
| 38fc340802 | |||
| b5f028e1f7 | |||
| aa40ddc48b | |||
| 6bcb40fe01 | |||
| e907db1481 | |||
| 6b8940421e | |||
| 2c71f08922 | |||
| 7e64bc8f77 | |||
| 1461563e3f | |||
| acdaa72365 | |||
| 01f5c1d455 | |||
| 00f3a65903 | |||
| b4815192a6 | |||
| c54e1cc955 | |||
| 7801921cc0 | |||
| afc6bd5cdd | |||
| ae2cbbf851 | |||
| ccd79ee289 | |||
| 171d0fe123 | |||
| 5ed0f67e1c | |||
| 8ce3cfad40 | |||
| 904fa852f6 | |||
| d0b2585e82 |
+19
-6
@@ -37,6 +37,13 @@ commands:
|
|||||||
sudo tar -C /usr/local -xf node-v10.15.1-linux-x64.tar.xz
|
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
|
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
|
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
|
||||||
llvm-source-linux:
|
llvm-source-linux:
|
||||||
steps:
|
steps:
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
@@ -71,6 +78,7 @@ commands:
|
|||||||
- apt-dependencies:
|
- apt-dependencies:
|
||||||
llvm: "<<parameters.llvm>>"
|
llvm: "<<parameters.llvm>>"
|
||||||
- install-node
|
- install-node
|
||||||
|
- install-chrome
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
- go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
||||||
@@ -85,9 +93,11 @@ commands:
|
|||||||
key: wasi-libc-sysroot-systemclang-v1
|
key: wasi-libc-sysroot-systemclang-v1
|
||||||
paths:
|
paths:
|
||||||
- lib/wasi-libc/sysroot
|
- lib/wasi-libc/sysroot
|
||||||
|
- run: tinygo clean
|
||||||
- run: go test -v -tags=llvm<<parameters.llvm>> ./cgo ./compileopts ./interp ./transform .
|
- run: go test -v -tags=llvm<<parameters.llvm>> ./cgo ./compileopts ./interp ./transform .
|
||||||
- run: make gen-device -j4
|
- run: make gen-device -j4
|
||||||
- run: make smoketest
|
- run: make smoketest
|
||||||
|
- run: make wasmtest
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
||||||
paths:
|
paths:
|
||||||
@@ -204,13 +214,21 @@ commands:
|
|||||||
- run:
|
- run:
|
||||||
name: "Test TinyGo"
|
name: "Test TinyGo"
|
||||||
command: make test
|
command: make test
|
||||||
|
- run:
|
||||||
|
name: "Install fpm"
|
||||||
|
command: |
|
||||||
|
sudo apt-get install ruby ruby-dev
|
||||||
|
sudo gem install --no-document fpm
|
||||||
- run:
|
- run:
|
||||||
name: "Build TinyGo release"
|
name: "Build TinyGo release"
|
||||||
command: |
|
command: |
|
||||||
make release -j3
|
make release deb -j3
|
||||||
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
|
cp -p build/release.tar.gz /tmp/tinygo.linux-amd64.tar.gz
|
||||||
|
cp -p build/release.deb /tmp/tinygo_amd64.deb
|
||||||
- store_artifacts:
|
- store_artifacts:
|
||||||
path: /tmp/tinygo.linux-amd64.tar.gz
|
path: /tmp/tinygo.linux-amd64.tar.gz
|
||||||
|
- store_artifacts:
|
||||||
|
path: /tmp/tinygo_amd64.deb
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
key: go-cache-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
||||||
paths:
|
paths:
|
||||||
@@ -294,11 +312,6 @@ commands:
|
|||||||
tar -C /usr/local/opt -xf /tmp/tinygo.darwin-amd64.tar.gz
|
tar -C /usr/local/opt -xf /tmp/tinygo.darwin-amd64.tar.gz
|
||||||
ln -s /usr/local/opt/tinygo/bin/tinygo /usr/local/bin/tinygo
|
ln -s /usr/local/opt/tinygo/bin/tinygo /usr/local/bin/tinygo
|
||||||
tinygo version
|
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
|
- run: make smoketest AVR=0
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: go-cache-macos-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
key: go-cache-macos-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
||||||
|
|||||||
+2
-5
@@ -4,7 +4,7 @@ FROM golang:1.14 AS tinygo-base
|
|||||||
RUN wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key| apt-key add - && \
|
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 && \
|
echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-10 main" >> /etc/apt/sources.list && \
|
||||||
apt-get update && \
|
apt-get update && \
|
||||||
apt-get install -y llvm-10-dev libclang-10-dev git
|
apt-get install -y llvm-10-dev libclang-10-dev lld-10 git
|
||||||
|
|
||||||
COPY . /tinygo
|
COPY . /tinygo
|
||||||
|
|
||||||
@@ -27,10 +27,7 @@ COPY --from=tinygo-base /go/bin/tinygo /go/bin/tinygo
|
|||||||
COPY --from=tinygo-base /tinygo/src /tinygo/src
|
COPY --from=tinygo-base /tinygo/src /tinygo/src
|
||||||
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
|
COPY --from=tinygo-base /tinygo/targets /tinygo/targets
|
||||||
|
|
||||||
RUN wget -O- https://apt.llvm.org/llvm-snapshot.gpg.key| apt-key add - && \
|
RUN apt-get install -y libllvm10 lld-10
|
||||||
echo "deb http://apt.llvm.org/buster/ llvm-toolchain-buster-10 main" >> /etc/apt/sources.list && \
|
|
||||||
apt-get update && \
|
|
||||||
apt-get install -y libllvm10 lld-10
|
|
||||||
|
|
||||||
# tinygo-avr stage installs the needed dependencies to compile TinyGo programs for AVR microcontrollers.
|
# tinygo-avr stage installs the needed dependencies to compile TinyGo programs for AVR microcontrollers.
|
||||||
FROM tinygo-base AS tinygo-avr
|
FROM tinygo-base AS tinygo-avr
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ tinygo-test:
|
|||||||
.PHONY: smoketest
|
.PHONY: smoketest
|
||||||
smoketest:
|
smoketest:
|
||||||
$(TINYGO) version
|
$(TINYGO) version
|
||||||
# test all examples
|
# test all examples (except pwm)
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/adc
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/adc
|
||||||
@@ -203,7 +203,7 @@ smoketest:
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=microbit examples/microbit-blink
|
$(TINYGO) build -size short -o test.hex -target=microbit examples/microbit-blink
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/pwm
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/pininterrupt
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/serial
|
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/serial
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
@@ -231,6 +231,8 @@ smoketest:
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=microbit examples/echo
|
$(TINYGO) build -size short -o test.hex -target=microbit examples/echo
|
||||||
@$(MD5SUM) test.hex
|
@$(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
|
$(TINYGO) build -size short -o test.hex -target=nrf52840-mdk examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10031 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=pca10031 examples/blinky1
|
||||||
@@ -291,11 +293,18 @@ smoketest:
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=reelboard-s140v7 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=reelboard-s140v7 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(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
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=xiao examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
ifneq ($(AVR), 0)
|
ifneq ($(AVR), 0)
|
||||||
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
|
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=arduino examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(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
|
$(TINYGO) build -size short -o test.hex -target=arduino -scheduler=tasks examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=arduino-nano examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=arduino-nano examples/blinky1
|
||||||
@@ -310,7 +319,10 @@ endif
|
|||||||
$(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/export
|
$(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/export
|
||||||
$(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/main
|
$(TINYGO) build -o wasm.wasm -target=wasm examples/wasm/main
|
||||||
|
|
||||||
release: tinygo gen-device wasi-libc
|
wasmtest:
|
||||||
|
$(GO) test ./tests/wasm
|
||||||
|
|
||||||
|
build/release: tinygo gen-device wasi-libc
|
||||||
@mkdir -p build/release/tinygo/bin
|
@mkdir -p build/release/tinygo/bin
|
||||||
@mkdir -p build/release/tinygo/lib/clang/include
|
@mkdir -p build/release/tinygo/lib/clang/include
|
||||||
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
|
@mkdir -p build/release/tinygo/lib/CMSIS/CMSIS
|
||||||
@@ -345,4 +357,13 @@ 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=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=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
|
./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
|
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,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
|
|||||||
|
|
||||||
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
||||||
|
|
||||||
The following 32 microcontroller boards are currently supported:
|
The following 34 microcontroller boards are currently supported:
|
||||||
|
|
||||||
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
||||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||||
@@ -72,6 +72,8 @@ The following 32 microcontroller boards are currently supported:
|
|||||||
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
|
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
|
||||||
* [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/)
|
* [Phytec reel board](https://www.phytec.eu/product-eu/internet-of-things/reelboard/)
|
||||||
* [PineTime DevKit](https://www.pine64.org/pinetime/)
|
* [PineTime DevKit](https://www.pine64.org/pinetime/)
|
||||||
|
* [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)
|
||||||
* [SiFIve HiFive1](https://www.sifive.com/boards/hifive1)
|
* [SiFIve HiFive1](https://www.sifive.com/boards/hifive1)
|
||||||
* [ST Micro "Nucleo F103RB"](https://www.st.com/en/evaluation-tools/nucleo-f103rb.html)
|
* [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)
|
* [ST Micro STM32F103XX "Bluepill"](http://wiki.stm32duino.com/index.php?title=Blue_Pill)
|
||||||
|
|||||||
+1
-1
@@ -69,7 +69,7 @@ jobs:
|
|||||||
script: |
|
script: |
|
||||||
export PATH="$PATH:./llvm-build/bin:/c/Program Files/qemu"
|
export PATH="$PATH:./llvm-build/bin:/c/Program Files/qemu"
|
||||||
unset GOROOT
|
unset GOROOT
|
||||||
make release -j4
|
make build/release -j4
|
||||||
- publish: $(System.DefaultWorkingDirectory)/build/release/tinygo
|
- publish: $(System.DefaultWorkingDirectory)/build/release/tinygo
|
||||||
displayName: Publish zip as artifact
|
displayName: Publish zip as artifact
|
||||||
artifact: tinygo
|
artifact: tinygo
|
||||||
|
|||||||
+5
-1
@@ -32,7 +32,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
mod, extraFiles, errs := compiler.Compile(pkgName, machine, config)
|
mod, extraFiles, extraLDFlags, errs := compiler.Compile(pkgName, machine, config)
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
return newMultiError(errs)
|
return newMultiError(errs)
|
||||||
}
|
}
|
||||||
@@ -187,6 +187,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(stri
|
|||||||
ldflags = append(ldflags, outpath)
|
ldflags = append(ldflags, outpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(extraLDFlags) > 0 {
|
||||||
|
ldflags = append(ldflags, extraLDFlags...)
|
||||||
|
}
|
||||||
|
|
||||||
// Link the object files together.
|
// Link the object files together.
|
||||||
err = link(config.Target.Linker, ldflags...)
|
err = link(config.Target.Linker, ldflags...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+8
-2
@@ -16,8 +16,10 @@ var genericBuiltins = []string{
|
|||||||
"addvsi3.c",
|
"addvsi3.c",
|
||||||
"addvti3.c",
|
"addvti3.c",
|
||||||
"apple_versioning.c",
|
"apple_versioning.c",
|
||||||
|
"ashlsi3.c",
|
||||||
"ashldi3.c",
|
"ashldi3.c",
|
||||||
"ashlti3.c",
|
"ashlti3.c",
|
||||||
|
"ashrsi3.c",
|
||||||
"ashrdi3.c",
|
"ashrdi3.c",
|
||||||
"ashrti3.c",
|
"ashrti3.c",
|
||||||
"bswapdi2.c",
|
"bswapdi2.c",
|
||||||
@@ -72,7 +74,9 @@ var genericBuiltins = []string{
|
|||||||
"floatunsisf.c",
|
"floatunsisf.c",
|
||||||
"floatuntidf.c",
|
"floatuntidf.c",
|
||||||
"floatuntisf.c",
|
"floatuntisf.c",
|
||||||
//"int_util.c",
|
"fp_mode.c",
|
||||||
|
"int_util.c",
|
||||||
|
"lshrsi3.c",
|
||||||
"lshrdi3.c",
|
"lshrdi3.c",
|
||||||
"lshrti3.c",
|
"lshrti3.c",
|
||||||
"moddi3.c",
|
"moddi3.c",
|
||||||
@@ -86,6 +90,7 @@ var genericBuiltins = []string{
|
|||||||
"muloti4.c",
|
"muloti4.c",
|
||||||
"mulsc3.c",
|
"mulsc3.c",
|
||||||
"mulsf3.c",
|
"mulsf3.c",
|
||||||
|
"mulsi3.c",
|
||||||
"multi3.c",
|
"multi3.c",
|
||||||
"multf3.c",
|
"multf3.c",
|
||||||
"mulvdi3.c",
|
"mulvdi3.c",
|
||||||
@@ -108,6 +113,7 @@ var genericBuiltins = []string{
|
|||||||
"powidf2.c",
|
"powidf2.c",
|
||||||
"powisf2.c",
|
"powisf2.c",
|
||||||
"powitf2.c",
|
"powitf2.c",
|
||||||
|
"powixf2.c",
|
||||||
"subdf3.c",
|
"subdf3.c",
|
||||||
"subsf3.c",
|
"subsf3.c",
|
||||||
"subvdi3.c",
|
"subvdi3.c",
|
||||||
@@ -159,7 +165,7 @@ var aeabiBuiltins = []string{
|
|||||||
var CompilerRT = Library{
|
var CompilerRT = Library{
|
||||||
name: "compiler-rt",
|
name: "compiler-rt",
|
||||||
cflags: func() []string { return []string{"-Werror", "-Wall", "-std=c11", "-nostdlibinc"} },
|
cflags: func() []string { return []string{"-Werror", "-Wall", "-std=c11", "-nostdlibinc"} },
|
||||||
sourceDir: "lib/compiler-rt/lib/builtins",
|
sourceDir: "llvm-project.master/compiler-rt/lib/builtins",
|
||||||
sources: func(target string) []string {
|
sources: func(target string) []string {
|
||||||
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
|
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
|
||||||
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
||||||
|
|||||||
+4
-1
@@ -69,11 +69,14 @@ func (l *Library) Load(target string) (path string, err error) {
|
|||||||
// Precalculate the flags to the compiler invocation.
|
// 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)
|
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") {
|
if strings.HasPrefix(target, "arm") || strings.HasPrefix(target, "thumb") {
|
||||||
args = append(args, "-fshort-enums", "-fomit-frame-pointer")
|
args = append(args, "-fshort-enums", "-fomit-frame-pointer", "-mfloat-abi=soft")
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(target, "riscv32-") {
|
if strings.HasPrefix(target, "riscv32-") {
|
||||||
args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128")
|
args = append(args, "-march=rv32imac", "-mabi=ilp32", "-fforce-enable-int128")
|
||||||
}
|
}
|
||||||
|
if strings.HasPrefix(target, "avr-") {
|
||||||
|
args = append(args, "-mdouble=64", "-mmcu=atmega1284p")
|
||||||
|
}
|
||||||
|
|
||||||
// Compile all sources.
|
// Compile all sources.
|
||||||
var objs []string
|
var objs []string
|
||||||
|
|||||||
+1
-2
@@ -123,8 +123,7 @@ func objcopy(infile, outfile string) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return objcopyError{"failed to create .hex file", err}
|
return objcopyError{"failed to create .hex file", err}
|
||||||
}
|
}
|
||||||
mem.DumpIntelHex(f, 16) // TODO: handle error
|
return mem.DumpIntelHex(f, 16)
|
||||||
return nil
|
|
||||||
default:
|
default:
|
||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-3
@@ -41,6 +41,7 @@ type cgoPackage struct {
|
|||||||
elaboratedTypes map[string]*elaboratedTypeInfo
|
elaboratedTypes map[string]*elaboratedTypeInfo
|
||||||
enums map[string]enumInfo
|
enums map[string]enumInfo
|
||||||
anonStructNum int
|
anonStructNum int
|
||||||
|
ldflags []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// constantInfo stores some information about a CGo constant found by libclang
|
// constantInfo stores some information about a CGo constant found by libclang
|
||||||
@@ -156,7 +157,7 @@ typedef unsigned long long _Cgo_ulonglong;
|
|||||||
// newly created *ast.File that should be added to the list of to-be-parsed
|
// 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
|
// files. If there is one or more error, it returns these in the []error slice
|
||||||
// but still modifies the AST.
|
// but still modifies the AST.
|
||||||
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string) (*ast.File, []error) {
|
func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string) (*ast.File, []string, []error) {
|
||||||
p := &cgoPackage{
|
p := &cgoPackage{
|
||||||
dir: dir,
|
dir: dir,
|
||||||
fset: fset,
|
fset: fset,
|
||||||
@@ -183,7 +184,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
|||||||
// Find the absolute path for this package.
|
// Find the absolute path for this package.
|
||||||
packagePath, err := filepath.Abs(fset.File(files[0].Pos()).Name())
|
packagePath, err := filepath.Abs(fset.File(files[0].Pos()).Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, []error{
|
return nil, nil, []error{
|
||||||
scanner.Error{
|
scanner.Error{
|
||||||
Pos: fset.Position(files[0].Pos()),
|
Pos: fset.Position(files[0].Pos()),
|
||||||
Msg: "cgo: cannot find absolute path: " + err.Error(), // TODO: wrap this error
|
Msg: "cgo: cannot find absolute path: " + err.Error(), // TODO: wrap this error
|
||||||
@@ -359,6 +360,19 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
|||||||
}
|
}
|
||||||
makePathsAbsolute(flags, packagePath)
|
makePathsAbsolute(flags, packagePath)
|
||||||
cflags = append(cflags, flags...)
|
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:
|
default:
|
||||||
startPos := strings.LastIndex(line[4:colon], name) + 4
|
startPos := strings.LastIndex(line[4:colon], name) + 4
|
||||||
p.addErrorAfter(comment.Slash, comment.Text[:lineStart+startPos], "invalid #cgo line: "+name)
|
p.addErrorAfter(comment.Slash, comment.Text[:lineStart+startPos], "invalid #cgo line: "+name)
|
||||||
@@ -412,7 +426,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
|
|||||||
// Print the newly generated in-memory AST, for debugging.
|
// Print the newly generated in-memory AST, for debugging.
|
||||||
//ast.Print(fset, p.generated)
|
//ast.Print(fset, p.generated)
|
||||||
|
|
||||||
return p.generated, p.errors
|
return p.generated, p.ldflags, p.errors
|
||||||
}
|
}
|
||||||
|
|
||||||
// makePathsAbsolute converts some common path compiler flags (-I, -L) from
|
// 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.
|
// 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.
|
// Check the AST for type errors.
|
||||||
var typecheckErrors []error
|
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):]
|
value := source[len(name):]
|
||||||
// Try to convert this #define into a Go constant expression.
|
// Try to convert this #define into a Go constant expression.
|
||||||
expr, err := parseConst(pos+token.Pos(len(name)), p.fset, value)
|
expr, scannerError := parseConst(pos+token.Pos(len(name)), p.fset, value)
|
||||||
if err != nil {
|
if scannerError != nil {
|
||||||
p.errors = append(p.errors, err)
|
p.errors = append(p.errors, *scannerError)
|
||||||
}
|
}
|
||||||
if expr != nil {
|
if expr != nil {
|
||||||
// Parsing was successful.
|
// Parsing was successful.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// +build !byollvm
|
// +build !byollvm
|
||||||
// +build !llvm9
|
// +build !llvm9,!llvm11
|
||||||
|
|
||||||
package cgo
|
package cgo
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// +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,6 +21,13 @@ package main
|
|||||||
#if defined(NOTDEFINED)
|
#if defined(NOTDEFINED)
|
||||||
#warning flag must not be defined
|
#warning flag must not be defined
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Check Compiler flags
|
||||||
|
#cgo LDFLAGS: -lc
|
||||||
|
|
||||||
|
// This flag is not valid ldflags
|
||||||
|
#cgo LDFLAGS: -does-not-exists
|
||||||
|
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
@@ -1,6 +1,7 @@
|
|||||||
// CGo errors:
|
// CGo errors:
|
||||||
// testdata/flags.go:5:7: invalid #cgo line: NOFLAGS
|
// testdata/flags.go:5:7: invalid #cgo line: NOFLAGS
|
||||||
// testdata/flags.go:8:13: invalid flag: -fdoes-not-exist
|
// testdata/flags.go:8:13: invalid flag: -fdoes-not-exist
|
||||||
|
// testdata/flags.go:29:14: invalid flag: -does-not-exists
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|||||||
+11
-2
@@ -129,8 +129,8 @@ func (c *Config) NeedsStackObjects() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scheduler returns the scheduler implementation. Valid values are "coroutines"
|
// Scheduler returns the scheduler implementation. Valid values are "none",
|
||||||
// and "tasks".
|
//"coroutines" and "tasks".
|
||||||
func (c *Config) Scheduler() string {
|
func (c *Config) Scheduler() string {
|
||||||
if c.Options.Scheduler != "" {
|
if c.Options.Scheduler != "" {
|
||||||
return c.Options.Scheduler
|
return c.Options.Scheduler
|
||||||
@@ -272,6 +272,15 @@ func (c *Config) OpenOCDConfiguration() (args []string, err error) {
|
|||||||
return args, nil
|
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"
|
||||||
|
}
|
||||||
|
|
||||||
type TestConfig struct {
|
type TestConfig struct {
|
||||||
CompileTestBinary bool
|
CompileTestBinary bool
|
||||||
// TODO: Filter the test functions to run, include verbose flag, etc
|
// TODO: Filter the test functions to run, include verbose flag, etc
|
||||||
|
|||||||
@@ -1,5 +1,17 @@
|
|||||||
package compileopts
|
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
|
// Options contains extra options to give to the compiler. These options are
|
||||||
// usually passed from the command line.
|
// usually passed from the command line.
|
||||||
type Options struct {
|
type Options struct {
|
||||||
@@ -21,3 +33,53 @@ type Options struct {
|
|||||||
TestConfig TestConfig
|
TestConfig TestConfig
|
||||||
Programmer string
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,6 +49,7 @@ type TargetSpec struct {
|
|||||||
OpenOCDTarget string `json:"openocd-target"`
|
OpenOCDTarget string `json:"openocd-target"`
|
||||||
OpenOCDTransport string `json:"openocd-transport"`
|
OpenOCDTransport string `json:"openocd-transport"`
|
||||||
JLinkDevice string `json:"jlink-device"`
|
JLinkDevice string `json:"jlink-device"`
|
||||||
|
CodeModel string `json:"code-model"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyProperties copies all properties that are set in spec2 into itself.
|
// copyProperties copies all properties that are set in spec2 into itself.
|
||||||
@@ -130,6 +131,9 @@ func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) {
|
|||||||
if spec2.JLinkDevice != "" {
|
if spec2.JLinkDevice != "" {
|
||||||
spec.JLinkDevice = spec2.JLinkDevice
|
spec.JLinkDevice = spec2.JLinkDevice
|
||||||
}
|
}
|
||||||
|
if spec2.CodeModel != "" {
|
||||||
|
spec.CodeModel = spec2.CodeModel
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// load reads a target specification from the JSON in the given io.Reader. It
|
// load reads a target specification from the JSON in the given io.Reader. It
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
-7
@@ -12,7 +12,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (b *builder) createMakeChan(expr *ssa.MakeChan) llvm.Value {
|
func (b *builder) createMakeChan(expr *ssa.MakeChan) llvm.Value {
|
||||||
elementSize := b.targetData.TypeAllocSize(b.getLLVMType(expr.Type().(*types.Chan).Elem()))
|
elementSize := b.targetData.TypeAllocSize(b.getLLVMType(expr.Type().Underlying().(*types.Chan).Elem()))
|
||||||
elementSizeValue := llvm.ConstInt(b.uintptrType, elementSize, false)
|
elementSizeValue := llvm.ConstInt(b.uintptrType, elementSize, false)
|
||||||
bufSize := b.getValue(expr.Size)
|
bufSize := b.getValue(expr.Size)
|
||||||
b.createChanBoundsCheck(elementSize, bufSize, expr.Size.Type().Underlying().(*types.Basic), expr.Pos())
|
b.createChanBoundsCheck(elementSize, bufSize, expr.Size.Type().Underlying().(*types.Basic), expr.Pos())
|
||||||
@@ -35,27 +35,37 @@ func (b *builder) createChanSend(instr *ssa.Send) {
|
|||||||
valueAlloca, valueAllocaCast, valueAllocaSize := b.createTemporaryAlloca(valueType, "chan.value")
|
valueAlloca, valueAllocaCast, valueAllocaSize := b.createTemporaryAlloca(valueType, "chan.value")
|
||||||
b.CreateStore(chanValue, valueAlloca)
|
b.CreateStore(chanValue, valueAlloca)
|
||||||
|
|
||||||
// Do the send.
|
// Allocate blockedlist buffer.
|
||||||
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAllocaCast}, "")
|
channelBlockedList := b.mod.GetTypeByName("runtime.channelBlockedList")
|
||||||
|
channelBlockedListAlloca, channelBlockedListAllocaCast, channelBlockedListAllocaSize := b.createTemporaryAlloca(channelBlockedList, "chan.blockedList")
|
||||||
|
|
||||||
// End the lifetime of the alloca.
|
// Do the send.
|
||||||
|
b.createRuntimeCall("chanSend", []llvm.Value{ch, valueAllocaCast, channelBlockedListAlloca}, "")
|
||||||
|
|
||||||
|
// End the lifetime of the allocas.
|
||||||
// This also works around a bug in CoroSplit, at least in LLVM 8:
|
// This also works around a bug in CoroSplit, at least in LLVM 8:
|
||||||
// https://bugs.llvm.org/show_bug.cgi?id=41742
|
// https://bugs.llvm.org/show_bug.cgi?id=41742
|
||||||
|
b.emitLifetimeEnd(channelBlockedListAllocaCast, channelBlockedListAllocaSize)
|
||||||
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
|
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
// createChanRecv emits a pseudo chan receive operation. It is lowered to the
|
// createChanRecv emits a pseudo chan receive operation. It is lowered to the
|
||||||
// actual channel receive operation during goroutine lowering.
|
// actual channel receive operation during goroutine lowering.
|
||||||
func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
|
func (b *builder) createChanRecv(unop *ssa.UnOp) llvm.Value {
|
||||||
valueType := b.getLLVMType(unop.X.Type().(*types.Chan).Elem())
|
valueType := b.getLLVMType(unop.X.Type().Underlying().(*types.Chan).Elem())
|
||||||
ch := b.getValue(unop.X)
|
ch := b.getValue(unop.X)
|
||||||
|
|
||||||
// Allocate memory to receive into.
|
// Allocate memory to receive into.
|
||||||
valueAlloca, valueAllocaCast, valueAllocaSize := b.createTemporaryAlloca(valueType, "chan.value")
|
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.
|
// Do the receive.
|
||||||
commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAllocaCast}, "")
|
commaOk := b.createRuntimeCall("chanRecv", []llvm.Value{ch, valueAllocaCast, channelBlockedListAlloca}, "")
|
||||||
received := b.CreateLoad(valueAlloca, "chan.received")
|
received := b.CreateLoad(valueAlloca, "chan.received")
|
||||||
|
b.emitLifetimeEnd(channelBlockedListAllocaCast, channelBlockedListAllocaSize)
|
||||||
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
|
b.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
|
||||||
|
|
||||||
if unop.CommaOk {
|
if unop.CommaOk {
|
||||||
@@ -117,7 +127,7 @@ func (b *builder) createSelect(expr *ssa.Select) llvm.Value {
|
|||||||
switch state.Dir {
|
switch state.Dir {
|
||||||
case types.RecvOnly:
|
case types.RecvOnly:
|
||||||
// Make sure the receive buffer is big enough and has the correct alignment.
|
// Make sure the receive buffer is big enough and has the correct alignment.
|
||||||
llvmType := b.getLLVMType(state.Chan.Type().(*types.Chan).Elem())
|
llvmType := b.getLLVMType(state.Chan.Type().Underlying().(*types.Chan).Elem())
|
||||||
if size := b.targetData.TypeAllocSize(llvmType); size > recvbufSize {
|
if size := b.targetData.TypeAllocSize(llvmType); size > recvbufSize {
|
||||||
recvbufSize = size
|
recvbufSize = size
|
||||||
}
|
}
|
||||||
|
|||||||
+42
-20
@@ -91,7 +91,25 @@ func NewTargetMachine(config *compileopts.Config) (llvm.TargetMachine, error) {
|
|||||||
return llvm.TargetMachine{}, err
|
return llvm.TargetMachine{}, err
|
||||||
}
|
}
|
||||||
features := strings.Join(config.Features(), ",")
|
features := strings.Join(config.Features(), ",")
|
||||||
machine := target.CreateTargetMachine(config.Triple(), config.CPU(), features, llvm.CodeGenLevelDefault, llvm.RelocStatic, llvm.CodeModelDefault)
|
|
||||||
|
var codeModel llvm.CodeModel
|
||||||
|
|
||||||
|
switch config.CodeModel() {
|
||||||
|
case "default":
|
||||||
|
codeModel = llvm.CodeModelDefault
|
||||||
|
case "tiny":
|
||||||
|
codeModel = llvm.CodeModelTiny
|
||||||
|
case "small":
|
||||||
|
codeModel = llvm.CodeModelSmall
|
||||||
|
case "kernel":
|
||||||
|
codeModel = llvm.CodeModelKernel
|
||||||
|
case "medium":
|
||||||
|
codeModel = llvm.CodeModelMedium
|
||||||
|
case "large":
|
||||||
|
codeModel = llvm.CodeModelLarge
|
||||||
|
}
|
||||||
|
|
||||||
|
machine := target.CreateTargetMachine(config.Triple(), config.CPU(), features, llvm.CodeGenLevelDefault, llvm.RelocStatic, codeModel)
|
||||||
return machine, nil
|
return machine, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +121,7 @@ func NewTargetMachine(config *compileopts.Config) (llvm.TargetMachine, error) {
|
|||||||
// violation. Eventually, this Compile function should only compile a single
|
// violation. Eventually, this Compile function should only compile a single
|
||||||
// package and not the whole program, and loading of the program (including CGo
|
// package and not the whole program, and loading of the program (including CGo
|
||||||
// processing) should be moved outside the compiler package.
|
// processing) should be moved outside the compiler package.
|
||||||
func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Config) (llvm.Module, []string, []error) {
|
func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Config) (mod llvm.Module, extrafiles []string, extraldflags []string, errors []error) {
|
||||||
c := &compilerContext{
|
c := &compilerContext{
|
||||||
Config: config,
|
Config: config,
|
||||||
difiles: make(map[string]llvm.Metadata),
|
difiles: make(map[string]llvm.Metadata),
|
||||||
@@ -139,11 +157,11 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
|
|||||||
|
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.mod, nil, []error{err}
|
return c.mod, nil, nil, []error{err}
|
||||||
}
|
}
|
||||||
goroot, err := loader.GetCachedGoroot(c.Config)
|
goroot, err := loader.GetCachedGoroot(c.Config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.mod, nil, []error{err}
|
return c.mod, nil, nil, []error{err}
|
||||||
}
|
}
|
||||||
lprogram := &loader.Program{
|
lprogram := &loader.Program{
|
||||||
Build: &build.Context{
|
Build: &build.Context{
|
||||||
@@ -172,12 +190,12 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
|
|||||||
|
|
||||||
err = lprogram.Load(pkgName)
|
err = lprogram.Load(pkgName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.mod, nil, []error{err}
|
return c.mod, nil, nil, []error{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = lprogram.Parse()
|
err = lprogram.Parse()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.mod, nil, []error{err}
|
return c.mod, nil, nil, []error{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.ir = ir.NewProgram(lprogram)
|
c.ir = ir.NewProgram(lprogram)
|
||||||
@@ -185,7 +203,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
|
|||||||
// Run a simple dead code elimination pass.
|
// Run a simple dead code elimination pass.
|
||||||
err = c.ir.SimpleDCE()
|
err = c.ir.SimpleDCE()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return c.mod, nil, []error{err}
|
return c.mod, nil, nil, []error{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize debug information.
|
// Initialize debug information.
|
||||||
@@ -332,7 +350,7 @@ func Compile(pkgName string, machine llvm.TargetMachine, config *compileopts.Con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.mod, extraFiles, c.diagnostics
|
return c.mod, extraFiles, lprogram.LDFlags, c.diagnostics
|
||||||
}
|
}
|
||||||
|
|
||||||
// getLLVMRuntimeType obtains a named type from the runtime package and returns
|
// getLLVMRuntimeType obtains a named type from the runtime package and returns
|
||||||
@@ -1053,7 +1071,7 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
|
|||||||
// goroutine:
|
// goroutine:
|
||||||
// * The function context, for closures.
|
// * The function context, for closures.
|
||||||
// * The function pointer (for tasks).
|
// * The function pointer (for tasks).
|
||||||
funcPtr, context := b.decodeFuncValue(b.getValue(instr.Call.Value), instr.Call.Value.Type().(*types.Signature))
|
funcPtr, context := b.decodeFuncValue(b.getValue(instr.Call.Value), instr.Call.Value.Type().Underlying().(*types.Signature))
|
||||||
params = append(params, context) // context parameter
|
params = append(params, context) // context parameter
|
||||||
switch b.Scheduler() {
|
switch b.Scheduler() {
|
||||||
case "none", "coroutines":
|
case "none", "coroutines":
|
||||||
@@ -1150,9 +1168,7 @@ func (b *builder) createBuiltin(args []ssa.Value, callName string, pos token.Pos
|
|||||||
var llvmCap llvm.Value
|
var llvmCap llvm.Value
|
||||||
switch args[0].Type().(type) {
|
switch args[0].Type().(type) {
|
||||||
case *types.Chan:
|
case *types.Chan:
|
||||||
// Channel. Buffered channels haven't been implemented yet so always
|
llvmCap = b.createRuntimeCall("chanCap", []llvm.Value{value}, "cap")
|
||||||
// return 0.
|
|
||||||
llvmCap = llvm.ConstInt(b.intType, 0, false)
|
|
||||||
case *types.Slice:
|
case *types.Slice:
|
||||||
llvmCap = b.CreateExtractValue(value, 2, "cap")
|
llvmCap = b.CreateExtractValue(value, 2, "cap")
|
||||||
default:
|
default:
|
||||||
@@ -1208,9 +1224,7 @@ func (b *builder) createBuiltin(args []ssa.Value, callName string, pos token.Pos
|
|||||||
// string or slice
|
// string or slice
|
||||||
llvmLen = b.CreateExtractValue(value, 1, "len")
|
llvmLen = b.CreateExtractValue(value, 1, "len")
|
||||||
case *types.Chan:
|
case *types.Chan:
|
||||||
// Channel. Buffered channels haven't been implemented yet so always
|
llvmLen = b.createRuntimeCall("chanLen", []llvm.Value{value}, "len")
|
||||||
// return 0.
|
|
||||||
llvmLen = llvm.ConstInt(b.intType, 0, false)
|
|
||||||
case *types.Map:
|
case *types.Map:
|
||||||
llvmLen = b.createRuntimeCall("hashmapLen", []llvm.Value{value}, "len")
|
llvmLen = b.createRuntimeCall("hashmapLen", []llvm.Value{value}, "len")
|
||||||
default:
|
default:
|
||||||
@@ -1313,9 +1327,9 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
return b.createMemoryCopyCall(fn, instr.Args)
|
return b.createMemoryCopyCall(fn, instr.Args)
|
||||||
case name == "runtime.memzero":
|
case name == "runtime.memzero":
|
||||||
return b.createMemoryZeroCall(instr.Args)
|
return b.createMemoryZeroCall(instr.Args)
|
||||||
case name == "device/arm.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm":
|
case name == "device.Asm" || name == "device/arm.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm":
|
||||||
return b.createInlineAsm(instr.Args)
|
return b.createInlineAsm(instr.Args)
|
||||||
case name == "device/arm.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
|
case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull":
|
||||||
return b.createInlineAsmFull(instr)
|
return b.createInlineAsmFull(instr)
|
||||||
case strings.HasPrefix(name, "device/arm.SVCall"):
|
case strings.HasPrefix(name, "device/arm.SVCall"):
|
||||||
return b.emitSVCall(instr.Args)
|
return b.emitSVCall(instr.Args)
|
||||||
@@ -1327,6 +1341,14 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
return b.createVolatileLoad(instr)
|
return b.createVolatileLoad(instr)
|
||||||
case strings.HasPrefix(name, "runtime/volatile.Store"):
|
case strings.HasPrefix(name, "runtime/volatile.Store"):
|
||||||
return b.createVolatileStore(instr)
|
return b.createVolatileStore(instr)
|
||||||
|
case strings.HasPrefix(name, "sync/atomic."):
|
||||||
|
val, ok := b.createAtomicOp(instr)
|
||||||
|
if ok {
|
||||||
|
// This call could be lowered as an atomic operation.
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
// This call couldn't be lowered as an atomic operation, it's
|
||||||
|
// probably something else. Continue as usual.
|
||||||
case name == "runtime/interrupt.New":
|
case name == "runtime/interrupt.New":
|
||||||
return b.createInterruptGlobal(instr)
|
return b.createInterruptGlobal(instr)
|
||||||
}
|
}
|
||||||
@@ -1520,7 +1542,7 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
index := b.getValue(expr.Index)
|
index := b.getValue(expr.Index)
|
||||||
|
|
||||||
// Check bounds.
|
// Check bounds.
|
||||||
arrayLen := expr.X.Type().(*types.Array).Len()
|
arrayLen := expr.X.Type().Underlying().(*types.Array).Len()
|
||||||
arrayLenLLVM := llvm.ConstInt(b.uintptrType, uint64(arrayLen), false)
|
arrayLenLLVM := llvm.ConstInt(b.uintptrType, uint64(arrayLen), false)
|
||||||
b.createLookupBoundsCheck(arrayLenLLVM, index, expr.Index.Type())
|
b.createLookupBoundsCheck(arrayLenLLVM, index, expr.Index.Type())
|
||||||
|
|
||||||
@@ -1632,8 +1654,8 @@ func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Bounds checking.
|
// Bounds checking.
|
||||||
lenType := expr.Len.Type().(*types.Basic)
|
lenType := expr.Len.Type().Underlying().(*types.Basic)
|
||||||
capType := expr.Cap.Type().(*types.Basic)
|
capType := expr.Cap.Type().Underlying().(*types.Basic)
|
||||||
b.createSliceBoundsCheck(maxSize, sliceLen, sliceCap, sliceCap, lenType, capType, capType)
|
b.createSliceBoundsCheck(maxSize, sliceLen, sliceCap, sliceCap, lenType, capType, capType)
|
||||||
|
|
||||||
// Allocate the backing array.
|
// Allocate the backing array.
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ go 1.11
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
||||||
|
github.com/chromedp/cdproto v0.0.0-20200116234248-4da64dd111ac
|
||||||
|
github.com/chromedp/chromedp v0.5.3
|
||||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf
|
||||||
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46
|
github.com/marcinbor85/gohex v0.0.0-20200531091804-343a4b548892
|
||||||
go.bug.st/serial v1.0.0
|
go.bug.st/serial v1.0.0
|
||||||
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2
|
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2
|
||||||
google.golang.org/appengine v1.4.0 // indirect
|
tinygo.org/x/go-llvm v0.0.0-20200503224449-70c558526021
|
||||||
tinygo.org/x/go-llvm v0.0.0-20200401165421-8d120882fc7a
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,13 +1,26 @@
|
|||||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
|
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/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||||
|
github.com/chromedp/cdproto v0.0.0-20200116234248-4da64dd111ac h1:T7V5BXqnYd55Hj/g5uhDYumg9Fp3rMTS6bykYtTIFX4=
|
||||||
|
github.com/chromedp/cdproto v0.0.0-20200116234248-4da64dd111ac/go.mod h1:PfAWWKJqjlGFYJEidUM6aVIWPr0EpobeyVWEEmplX7g=
|
||||||
|
github.com/chromedp/chromedp v0.5.3 h1:F9LafxmYpsQhWQBdCs+6Sret1zzeeFyHS5LkRF//Ffg=
|
||||||
|
github.com/chromedp/chromedp v0.5.3/go.mod h1:YLdPtndaHQ4rCpSpBG+IPpy9JvX0VD+7aaLxYgYj28w=
|
||||||
github.com/creack/goselect v0.1.1 h1:tiSSgKE1eJtxs1h/VgGQWuXUP0YS4CDIFMp6vaI1ls0=
|
github.com/creack/goselect v0.1.1 h1:tiSSgKE1eJtxs1h/VgGQWuXUP0YS4CDIFMp6vaI1ls0=
|
||||||
github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
|
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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
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.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo=
|
||||||
|
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
|
||||||
github.com/google/shlex v0.0.0-20181106134648-c34317bd91bf h1:7+FW5aGwISbqUtkfmIpZJGRgNFg2ioYPvFaUxdqpDsg=
|
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/google/shlex v0.0.0-20181106134648-c34317bd91bf/go.mod h1:RpwtwJQFrIEPstU94h88MWPXP2ektJZ8cZ0YntAmXiE=
|
||||||
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46 h1:wXG2bA8fO7Vv7lLk2PihFMTqmbT173Tje39oKzQ50Mo=
|
github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08 h1:V0an7KRw92wmJysvFvtqtKMAPmvS5O0jtB0nYo6t+gs=
|
||||||
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
|
github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08/go.mod h1:dFWs1zEqDjFtnBXsd1vPOZaLsESovai349994nHx3e0=
|
||||||
|
github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM=
|
||||||
|
github.com/mailru/easyjson v0.7.0/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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
@@ -17,43 +30,21 @@ 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/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 h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
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-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/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/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-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-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 h1:ZBzSG/7F4eNKz2L3GE9o300RX0Az1Bw5HF7PDraD+qU=
|
||||||
golang.org/x/sys v0.0.0-20191128015809-6d18c012aee9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
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/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 h1:0sfSpGSa544Fwnbot3Oxq/U6SXqjty6Jy/3wRhVS7ig=
|
||||||
golang.org/x/tools v0.0.0-20200216192241-b320d3a0f5a2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
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 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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/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=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261 h1:rJS2Hga39YAnm7DE4qrPm6Dr/67EOojL0XPzvbEeBiw=
|
tinygo.org/x/go-llvm v0.0.0-20200503224449-70c558526021 h1:d8T98WXGjrTgDmMXgxa6nb9EAYXGXwnzXygnJl6d+ac=
|
||||||
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
|
tinygo.org/x/go-llvm v0.0.0-20200503224449-70c558526021/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=
|
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Version of TinyGo.
|
||||||
|
// Update this value before release of new version of software.
|
||||||
|
const Version = "0.14.0-dev"
|
||||||
|
|
||||||
// GetGorootVersion returns the major and minor version for a given GOROOT path.
|
// GetGorootVersion returns the major and minor version for a given GOROOT path.
|
||||||
// If the goroot cannot be determined, (0, 0) is returned.
|
// If the goroot cannot be determined, (0, 0) is returned.
|
||||||
func GetGorootVersion(goroot string) (major, minor int, err error) {
|
func GetGorootVersion(goroot string) (major, minor int, err error) {
|
||||||
|
|||||||
@@ -67,48 +67,10 @@ func NewProgram(lprogram *loader.Program) *Program {
|
|||||||
program := lprogram.LoadSSA()
|
program := lprogram.LoadSSA()
|
||||||
program.Build()
|
program.Build()
|
||||||
|
|
||||||
// Find the main package, which is a bit difficult when running a .go file
|
|
||||||
// directly.
|
|
||||||
mainPkg := program.ImportedPackage(lprogram.MainPkg.PkgPath)
|
mainPkg := program.ImportedPackage(lprogram.MainPkg.PkgPath)
|
||||||
if mainPkg == nil {
|
if mainPkg == nil {
|
||||||
panic("could not find main package")
|
panic("could not find main package")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a list of packages in import order.
|
|
||||||
packageList := []*ssa.Package{}
|
|
||||||
packageSet := map[string]struct{}{}
|
|
||||||
worklist := []string{"runtime", lprogram.MainPkg.PkgPath}
|
|
||||||
for len(worklist) != 0 {
|
|
||||||
pkgPath := worklist[0]
|
|
||||||
pkg := program.ImportedPackage(pkgPath)
|
|
||||||
if _, ok := packageSet[pkgPath]; ok {
|
|
||||||
// Package already in the final package list.
|
|
||||||
worklist = worklist[1:]
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
unsatisfiedImports := make([]string, 0)
|
|
||||||
imports := pkg.Pkg.Imports()
|
|
||||||
for _, pkg := range imports {
|
|
||||||
if _, ok := packageSet[pkg.Path()]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
unsatisfiedImports = append(unsatisfiedImports, pkg.Path())
|
|
||||||
}
|
|
||||||
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 := &Program{
|
p := &Program{
|
||||||
Program: program,
|
Program: program,
|
||||||
LoaderProgram: lprogram,
|
LoaderProgram: lprogram,
|
||||||
@@ -116,8 +78,8 @@ func NewProgram(lprogram *loader.Program) *Program {
|
|||||||
functionMap: make(map[*ssa.Function]*Function),
|
functionMap: make(map[*ssa.Function]*Function),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, pkg := range packageList {
|
for _, pkg := range lprogram.Sorted() {
|
||||||
p.AddPackage(pkg)
|
p.AddPackage(program.ImportedPackage(pkg.PkgPath))
|
||||||
}
|
}
|
||||||
|
|
||||||
return p
|
return p
|
||||||
|
|||||||
+25
-10
@@ -7,6 +7,7 @@ import (
|
|||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
@@ -32,22 +33,24 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
|
|||||||
return "", errors.New("could not determine TINYGOROOT")
|
return "", errors.New("could not determine TINYGOROOT")
|
||||||
}
|
}
|
||||||
|
|
||||||
needsSyscallPackage := false
|
|
||||||
for _, tag := range config.BuildTags() {
|
|
||||||
if tag == "baremetal" || tag == "darwin" {
|
|
||||||
needsSyscallPackage = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine the location of the cached GOROOT.
|
// Determine the location of the cached GOROOT.
|
||||||
version, err := goenv.GorootVersionString(goroot)
|
version, err := goenv.GorootVersionString(goroot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
gorootsHash := sha512.Sum512_256([]byte(goroot + "\x00" + tinygoroot))
|
// 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[:])
|
gorootsHashHex := hex.EncodeToString(gorootsHash[:])
|
||||||
cachedgoroot := filepath.Join(goenv.Get("GOCACHE"), "goroot-"+version+"-"+gorootsHashHex)
|
cachedgoroot := filepath.Join(goenv.Get("GOCACHE"), "goroot-"+version+"-"+gorootsHashHex)
|
||||||
if needsSyscallPackage {
|
if needsSyscallPackage(config.BuildTags()) {
|
||||||
cachedgoroot += "-syscall"
|
cachedgoroot += "-syscall"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,7 +73,7 @@ func GetCachedGoroot(config *compileopts.Config) (string, error) {
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
err = mergeDirectory(goroot, tinygoroot, tmpgoroot, "", pathsToOverride(needsSyscallPackage))
|
err = mergeDirectory(goroot, tinygoroot, tmpgoroot, "", pathsToOverride(needsSyscallPackage(config.BuildTags())))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -158,6 +161,17 @@ func mergeDirectory(goroot, tinygoroot, tmpgoroot, importPath string, overrides
|
|||||||
return nil
|
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" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// The boolean indicates whether to merge the subdirs. True means merge, false
|
// The boolean indicates whether to merge the subdirs. True means merge, false
|
||||||
// means use the TinyGo version.
|
// means use the TinyGo version.
|
||||||
func pathsToOverride(needsSyscallPackage bool) map[string]bool {
|
func pathsToOverride(needsSyscallPackage bool) map[string]bool {
|
||||||
@@ -166,6 +180,7 @@ func pathsToOverride(needsSyscallPackage bool) map[string]bool {
|
|||||||
"device/": false,
|
"device/": false,
|
||||||
"examples/": false,
|
"examples/": false,
|
||||||
"internal/": true,
|
"internal/": true,
|
||||||
|
"internal/bytealg/": false,
|
||||||
"internal/reflectlite/": false,
|
"internal/reflectlite/": false,
|
||||||
"internal/task/": false,
|
"internal/task/": false,
|
||||||
"machine/": false,
|
"machine/": false,
|
||||||
|
|||||||
+57
-18
@@ -7,11 +7,13 @@ import (
|
|||||||
"go/ast"
|
"go/ast"
|
||||||
"go/build"
|
"go/build"
|
||||||
"go/parser"
|
"go/parser"
|
||||||
|
"go/scanner"
|
||||||
"go/token"
|
"go/token"
|
||||||
"go/types"
|
"go/types"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
@@ -32,6 +34,7 @@ type Program struct {
|
|||||||
Dir string // current working directory (for error reporting)
|
Dir string // current working directory (for error reporting)
|
||||||
TINYGOROOT string // root of the TinyGo installation or root of the source code
|
TINYGOROOT string // root of the TinyGo installation or root of the source code
|
||||||
CFlags []string
|
CFlags []string
|
||||||
|
LDFlags []string
|
||||||
ClangHeaders string
|
ClangHeaders string
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +118,26 @@ func (p *Program) loadPackage(importPath string) error {
|
|||||||
Pkg: pkg2,
|
Pkg: pkg2,
|
||||||
}
|
}
|
||||||
for _, err := range pkg.Errors {
|
for _, err := range pkg.Errors {
|
||||||
importError.Errs = append(importError.Errs, err)
|
pos := token.Position{}
|
||||||
|
fields := strings.Split(err.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)
|
||||||
|
}
|
||||||
|
importError.Errs = append(importError.Errs, scanner.Error{
|
||||||
|
Pos: pos,
|
||||||
|
Msg: err.Msg,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -136,11 +158,41 @@ func (p *Program) loadPackage(importPath string) error {
|
|||||||
}
|
}
|
||||||
addPackages(pkg)
|
addPackages(pkg)
|
||||||
if importError != nil {
|
if importError != nil {
|
||||||
return importError
|
return *importError
|
||||||
}
|
}
|
||||||
return nil
|
return 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.Build.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.Build.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.Build.BuildTags)) {
|
||||||
|
if !strings.HasPrefix(relpath, prefix) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
maybeInTinyGoRoot = true
|
||||||
|
}
|
||||||
|
if maybeInTinyGoRoot {
|
||||||
|
tinygoPath := filepath.Join(p.TINYGOROOT, "src", relpath)
|
||||||
|
if _, err := os.Stat(tinygoPath); err == nil {
|
||||||
|
originalPath = tinygoPath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return originalPath
|
||||||
|
}
|
||||||
|
|
||||||
// newPackage instantiates a new *Package object with initialized members.
|
// newPackage instantiates a new *Package object with initialized members.
|
||||||
func (p *Program) newPackage(pkg *packages.Package) *Package {
|
func (p *Program) newPackage(pkg *packages.Package) *Package {
|
||||||
return &Package{
|
return &Package{
|
||||||
@@ -282,21 +334,7 @@ func (p *Program) parseFile(path string, mode parser.Mode) (*ast.File, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer rd.Close()
|
defer rd.Close()
|
||||||
diagnosticPath := path
|
return parser.ParseFile(p.fset, p.getOriginalPath(path), rd, mode)
|
||||||
if strings.HasPrefix(path, p.Build.GOROOT+string(filepath.Separator)) {
|
|
||||||
// If this file is part of the synthetic GOROOT, try to infer the
|
|
||||||
// original path.
|
|
||||||
relpath := path[len(p.Build.GOROOT)+1:]
|
|
||||||
tinygoPath := filepath.Join(p.TINYGOROOT, relpath)
|
|
||||||
if _, err := os.Stat(tinygoPath); err == nil {
|
|
||||||
diagnosticPath = tinygoPath
|
|
||||||
}
|
|
||||||
realgorootPath := filepath.Join(goenv.Get("GOROOT"), relpath)
|
|
||||||
if _, err := os.Stat(realgorootPath); err == nil {
|
|
||||||
diagnosticPath = realgorootPath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return parser.ParseFile(p.fset, diagnosticPath, rd, mode)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses and typechecks this package.
|
// Parse parses and typechecks this package.
|
||||||
@@ -383,11 +421,12 @@ func (p *Package) parseFiles() ([]*ast.File, error) {
|
|||||||
if p.ClangHeaders != "" {
|
if p.ClangHeaders != "" {
|
||||||
cflags = append(cflags, "-Xclang", "-internal-isystem", "-Xclang", p.ClangHeaders)
|
cflags = append(cflags, "-Xclang", "-internal-isystem", "-Xclang", p.ClangHeaders)
|
||||||
}
|
}
|
||||||
generated, errs := cgo.Process(files, p.Program.Dir, p.fset, cflags)
|
generated, ldflags, errs := cgo.Process(files, p.Program.Dir, p.fset, cflags)
|
||||||
if errs != nil {
|
if errs != nil {
|
||||||
fileErrs = append(fileErrs, errs...)
|
fileErrs = append(fileErrs, errs...)
|
||||||
}
|
}
|
||||||
files = append(files, generated)
|
files = append(files, generated)
|
||||||
|
p.LDFlags = append(p.LDFlags, ldflags...)
|
||||||
}
|
}
|
||||||
if len(fileErrs) != 0 {
|
if len(fileErrs) != 0 {
|
||||||
return nil, Errors{p, fileErrs}
|
return nil, Errors{p, fileErrs}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -311,10 +310,12 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
|
|||||||
switch gdbInterface {
|
switch gdbInterface {
|
||||||
case "msd", "command", "":
|
case "msd", "command", "":
|
||||||
if len(config.Target.Emulator) != 0 {
|
if len(config.Target.Emulator) != 0 {
|
||||||
// Assume QEMU as an emulator.
|
|
||||||
if config.Target.Emulator[0] == "mgba" {
|
if config.Target.Emulator[0] == "mgba" {
|
||||||
gdbInterface = "mgba"
|
gdbInterface = "mgba"
|
||||||
|
} else if config.Target.Emulator[0] == "simavr" {
|
||||||
|
gdbInterface = "simavr"
|
||||||
} else {
|
} else {
|
||||||
|
// Assume QEMU as an emulator.
|
||||||
gdbInterface = "qemu"
|
gdbInterface = "qemu"
|
||||||
}
|
}
|
||||||
} else if openocdInterface != "" && config.Target.OpenOCDTarget != "" {
|
} else if openocdInterface != "" && config.Target.OpenOCDTarget != "" {
|
||||||
@@ -380,6 +381,14 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
|
|||||||
daemon = exec.Command(config.Target.Emulator[0], args...)
|
daemon = exec.Command(config.Target.Emulator[0], args...)
|
||||||
daemon.Stdout = os.Stdout
|
daemon.Stdout = os.Stdout
|
||||||
daemon.Stderr = os.Stderr
|
daemon.Stderr = os.Stderr
|
||||||
|
case "simavr":
|
||||||
|
gdbCommands = append(gdbCommands, "target remote :1234")
|
||||||
|
|
||||||
|
// Run in an emulator.
|
||||||
|
args := append(config.Target.Emulator[1:], "-g", tmppath)
|
||||||
|
daemon = exec.Command(config.Target.Emulator[0], args...)
|
||||||
|
daemon.Stdout = os.Stdout
|
||||||
|
daemon.Stderr = os.Stderr
|
||||||
case "msd":
|
case "msd":
|
||||||
return errors.New("gdb is not supported for drag-and-drop programmable devices")
|
return errors.New("gdb is not supported for drag-and-drop programmable devices")
|
||||||
default:
|
default:
|
||||||
@@ -480,6 +489,13 @@ func touchSerialPortAt1200bps(port string) (err error) {
|
|||||||
// Open port
|
// Open port
|
||||||
p, e := serial.Open(port, &serial.Mode{BaudRate: 1200})
|
p, e := serial.Open(port, &serial.Mode{BaudRate: 1200})
|
||||||
if e != nil {
|
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)
|
time.Sleep(1 * time.Second)
|
||||||
err = e
|
err = e
|
||||||
continue
|
continue
|
||||||
@@ -492,6 +508,8 @@ func touchSerialPortAt1200bps(port string) (err error) {
|
|||||||
return fmt.Errorf("opening port: %s", err)
|
return fmt.Errorf("opening port: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const maxMSDRetries = 10
|
||||||
|
|
||||||
func flashUF2UsingMSD(volume, tmppath string) error {
|
func flashUF2UsingMSD(volume, tmppath string) error {
|
||||||
// find standard UF2 info path
|
// find standard UF2 info path
|
||||||
var infoPath string
|
var infoPath string
|
||||||
@@ -508,15 +526,12 @@ func flashUF2UsingMSD(volume, tmppath string) error {
|
|||||||
infoPath = path + "/INFO_UF2.TXT"
|
infoPath = path + "/INFO_UF2.TXT"
|
||||||
}
|
}
|
||||||
|
|
||||||
d, err := filepath.Glob(infoPath)
|
d, err := locateDevice(volume, infoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if d == nil {
|
|
||||||
return errors.New("unable to locate UF2 device: " + volume)
|
|
||||||
}
|
|
||||||
|
|
||||||
return moveFile(tmppath, filepath.Dir(d[0])+"/flash.uf2")
|
return moveFile(tmppath, filepath.Dir(d)+"/flash.uf2")
|
||||||
}
|
}
|
||||||
|
|
||||||
func flashHexUsingMSD(volume, tmppath string) error {
|
func flashHexUsingMSD(volume, tmppath string) error {
|
||||||
@@ -535,15 +550,31 @@ func flashHexUsingMSD(volume, tmppath string) error {
|
|||||||
destPath = path + "/"
|
destPath = path + "/"
|
||||||
}
|
}
|
||||||
|
|
||||||
d, err := filepath.Glob(destPath)
|
d, err := locateDevice(volume, destPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if d == nil {
|
|
||||||
return errors.New("unable to locate device: " + volume)
|
|
||||||
}
|
|
||||||
|
|
||||||
return moveFile(tmppath, d[0]+"/flash.hex")
|
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 d[0], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func windowsFindUSBDrive(volume string) (string, error) {
|
func windowsFindUSBDrive(volume string) (string, error) {
|
||||||
@@ -604,29 +635,18 @@ func getDefaultPort() (port string, err error) {
|
|||||||
case "freebsd":
|
case "freebsd":
|
||||||
portPath = "/dev/cuaU*"
|
portPath = "/dev/cuaU*"
|
||||||
case "windows":
|
case "windows":
|
||||||
cmd := exec.Command("wmic",
|
ports, err := serial.GetPortsList()
|
||||||
"PATH", "Win32_SerialPort", "WHERE", "Caption LIKE 'USB Serial%'", "GET", "DeviceID")
|
|
||||||
|
|
||||||
var out bytes.Buffer
|
|
||||||
cmd.Stdout = &out
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if out.String() == "No Instance(s) Available." {
|
if len(ports) == 0 {
|
||||||
return "", errors.New("no serial ports available")
|
return "", errors.New("no serial ports available")
|
||||||
|
} else if len(ports) > 1 {
|
||||||
|
return "", errors.New("multiple serial ports available - use -port flag")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, line := range strings.Split(out.String(), "\n") {
|
return ports[0], nil
|
||||||
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:
|
default:
|
||||||
return "", errors.New("unable to search for a default USB device to be flashed on this OS")
|
return "", errors.New("unable to search for a default USB device to be flashed on this OS")
|
||||||
}
|
}
|
||||||
@@ -674,7 +694,7 @@ func runGoList(config *compileopts.Config, flagJSON, flagDeps bool, pkgs []strin
|
|||||||
|
|
||||||
func usage() {
|
func usage() {
|
||||||
fmt.Fprintln(os.Stderr, "TinyGo is a Go compiler for small places.")
|
fmt.Fprintln(os.Stderr, "TinyGo is a Go compiler for small places.")
|
||||||
fmt.Fprintln(os.Stderr, "version:", version)
|
fmt.Fprintln(os.Stderr, "version:", goenv.Version)
|
||||||
fmt.Fprintf(os.Stderr, "usage: %s command [-printir] [-target=<target>] -o <output> <input>\n", os.Args[0])
|
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, "\ncommands:")
|
||||||
fmt.Fprintln(os.Stderr, " build: compile packages and dependencies")
|
fmt.Fprintln(os.Stderr, " build: compile packages and dependencies")
|
||||||
@@ -690,6 +710,20 @@ func usage() {
|
|||||||
flag.PrintDefaults()
|
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
|
// printCompilerError prints compiler errors using the provided logger function
|
||||||
// (similar to fmt.Println).
|
// (similar to fmt.Println).
|
||||||
//
|
//
|
||||||
@@ -697,8 +731,24 @@ func usage() {
|
|||||||
// to limitations in the LLVM bindings.
|
// to limitations in the LLVM bindings.
|
||||||
func printCompilerError(logln func(...interface{}), err error) {
|
func printCompilerError(logln func(...interface{}), err error) {
|
||||||
switch err := err.(type) {
|
switch err := err.(type) {
|
||||||
case types.Error, scanner.Error:
|
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)
|
||||||
|
}
|
||||||
logln(err)
|
logln(err)
|
||||||
|
case scanner.ErrorList:
|
||||||
|
for _, scannerErr := range err {
|
||||||
|
printCompilerError(logln, *scannerErr)
|
||||||
|
}
|
||||||
case *interp.Error:
|
case *interp.Error:
|
||||||
logln("#", err.ImportPath)
|
logln("#", err.ImportPath)
|
||||||
logln(err.Error())
|
logln(err.Error())
|
||||||
@@ -717,11 +767,11 @@ func printCompilerError(logln func(...interface{}), err error) {
|
|||||||
case loader.Errors:
|
case loader.Errors:
|
||||||
logln("#", err.Pkg.PkgPath)
|
logln("#", err.Pkg.PkgPath)
|
||||||
for _, err := range err.Errs {
|
for _, err := range err.Errs {
|
||||||
logln(err)
|
printCompilerError(logln, err)
|
||||||
}
|
}
|
||||||
case *builder.MultiError:
|
case *builder.MultiError:
|
||||||
for _, err := range err.Errs {
|
for _, err := range err.Errs {
|
||||||
logln(err)
|
printCompilerError(logln, err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
logln("error:", err)
|
logln("error:", err)
|
||||||
@@ -749,7 +799,7 @@ func main() {
|
|||||||
opt := flag.String("opt", "z", "optimization level: 0, 1, 2, s, z")
|
opt := flag.String("opt", "z", "optimization level: 0, 1, 2, s, z")
|
||||||
gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, conservative)")
|
gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, conservative)")
|
||||||
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
|
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
|
||||||
scheduler := flag.String("scheduler", "", "which scheduler to use (coroutines, tasks)")
|
scheduler := flag.String("scheduler", "", "which scheduler to use (none, coroutines, tasks)")
|
||||||
printIR := flag.Bool("printir", false, "print LLVM IR")
|
printIR := flag.Bool("printir", false, "print LLVM IR")
|
||||||
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
|
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
|
||||||
verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR")
|
verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR")
|
||||||
@@ -766,10 +816,8 @@ func main() {
|
|||||||
heapSize := flag.String("heap-size", "1M", "default heap size in bytes (only supported by WebAssembly)")
|
heapSize := flag.String("heap-size", "1M", "default heap size in bytes (only supported by WebAssembly)")
|
||||||
|
|
||||||
var flagJSON, flagDeps *bool
|
var flagJSON, flagDeps *bool
|
||||||
if command == "list" || command == "env" {
|
|
||||||
flagJSON = flag.Bool("json", false, "print data in JSON format")
|
|
||||||
}
|
|
||||||
if command == "list" {
|
if command == "list" {
|
||||||
|
flagJSON = flag.Bool("json", false, "print data in JSON format")
|
||||||
flagDeps = flag.Bool("deps", false, "")
|
flagDeps = flag.Bool("deps", false, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,12 +858,6 @@ func main() {
|
|||||||
options.LDFlags = strings.Split(*ldFlags, " ")
|
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
|
var err error
|
||||||
if options.HeapSize, err = parseSize(*heapSize); err != nil {
|
if options.HeapSize, err = parseSize(*heapSize); err != nil {
|
||||||
fmt.Fprintln(os.Stderr, "Could not read heap size:", *heapSize)
|
fmt.Fprintln(os.Stderr, "Could not read heap size:", *heapSize)
|
||||||
@@ -825,6 +867,13 @@ func main() {
|
|||||||
|
|
||||||
os.Setenv("CC", "clang -target="+*target)
|
os.Setenv("CC", "clang -target="+*target)
|
||||||
|
|
||||||
|
err = options.Verify()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err.Error())
|
||||||
|
usage()
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
switch command {
|
switch command {
|
||||||
case "build":
|
case "build":
|
||||||
if *outpath == "" {
|
if *outpath == "" {
|
||||||
@@ -834,7 +883,7 @@ func main() {
|
|||||||
}
|
}
|
||||||
pkgName := "."
|
pkgName := "."
|
||||||
if flag.NArg() == 1 {
|
if flag.NArg() == 1 {
|
||||||
pkgName = flag.Arg(0)
|
pkgName = filepath.ToSlash(flag.Arg(0))
|
||||||
} else if flag.NArg() > 1 {
|
} else if flag.NArg() > 1 {
|
||||||
fmt.Fprintln(os.Stderr, "build only accepts a single positional argument: package name, but multiple were specified")
|
fmt.Fprintln(os.Stderr, "build only accepts a single positional argument: package name, but multiple were specified")
|
||||||
usage()
|
usage()
|
||||||
@@ -843,6 +892,7 @@ func main() {
|
|||||||
if options.Target == "" && filepath.Ext(*outpath) == ".wasm" {
|
if options.Target == "" && filepath.Ext(*outpath) == ".wasm" {
|
||||||
options.Target = "wasm"
|
options.Target = "wasm"
|
||||||
}
|
}
|
||||||
|
|
||||||
err := Build(pkgName, *outpath, options)
|
err := Build(pkgName, *outpath, options)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
case "build-library":
|
case "build-library":
|
||||||
@@ -879,8 +929,9 @@ func main() {
|
|||||||
usage()
|
usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
pkgName := filepath.ToSlash(flag.Arg(0))
|
||||||
if command == "flash" {
|
if command == "flash" {
|
||||||
err := Flash(flag.Arg(0), *port, options)
|
err := Flash(pkgName, *port, options)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
} else {
|
} else {
|
||||||
if !options.Debug {
|
if !options.Debug {
|
||||||
@@ -888,7 +939,7 @@ func main() {
|
|||||||
usage()
|
usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
err := FlashGDB(flag.Arg(0), *ocdOutput, options)
|
err := FlashGDB(pkgName, *ocdOutput, options)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
}
|
}
|
||||||
case "run":
|
case "run":
|
||||||
@@ -897,12 +948,13 @@ func main() {
|
|||||||
usage()
|
usage()
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
err := Run(flag.Arg(0), options)
|
pkgName := filepath.ToSlash(flag.Arg(0))
|
||||||
|
err := Run(pkgName, options)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
case "test":
|
case "test":
|
||||||
pkgName := "."
|
pkgName := "."
|
||||||
if flag.NArg() == 1 {
|
if flag.NArg() == 1 {
|
||||||
pkgName = flag.Arg(0)
|
pkgName = filepath.ToSlash(flag.Arg(0))
|
||||||
} else if flag.NArg() > 1 {
|
} else if flag.NArg() > 1 {
|
||||||
fmt.Fprintln(os.Stderr, "test only accepts a single positional argument: package name, but multiple were specified")
|
fmt.Fprintln(os.Stderr, "test only accepts a single positional argument: package name, but multiple were specified")
|
||||||
usage()
|
usage()
|
||||||
@@ -961,33 +1013,17 @@ func main() {
|
|||||||
if s, err := goenv.GorootVersionString(goenv.Get("GOROOT")); err == nil {
|
if s, err := goenv.GorootVersionString(goenv.Get("GOROOT")); err == nil {
|
||||||
goversion = s
|
goversion = s
|
||||||
}
|
}
|
||||||
fmt.Printf("tinygo version %s %s/%s (using go version %s and LLVM version %s)\n", version, runtime.GOOS, runtime.GOARCH, goversion, llvm.Version)
|
fmt.Printf("tinygo version %s %s/%s (using go version %s and LLVM version %s)\n", goenv.Version, runtime.GOOS, runtime.GOARCH, goversion, llvm.Version)
|
||||||
case "env":
|
case "env":
|
||||||
if *flagJSON {
|
if flag.NArg() == 0 {
|
||||||
keys := goenv.Keys
|
// Show all environment variables.
|
||||||
if flag.NArg() != 0 {
|
for _, key := range goenv.Keys {
|
||||||
// Show only one (or a few) environment variables.
|
fmt.Printf("%s=%#v\n", key, goenv.Get(key))
|
||||||
keys = flag.Args()
|
|
||||||
}
|
}
|
||||||
// Show environment variables in JSON format.
|
|
||||||
env := make(map[string]string)
|
|
||||||
for _, key := range keys {
|
|
||||||
env[key] = goenv.Get(key)
|
|
||||||
}
|
|
||||||
encoder := json.NewEncoder(os.Stdout)
|
|
||||||
encoder.SetIndent("", "\t")
|
|
||||||
encoder.Encode(env)
|
|
||||||
} else {
|
} else {
|
||||||
if flag.NArg() == 0 {
|
// Show only one (or a few) environment variables.
|
||||||
// Show all environment variables.
|
for i := 0; i < flag.NArg(); i++ {
|
||||||
for _, key := range goenv.Keys {
|
fmt.Println(goenv.Get(flag.Arg(i)))
|
||||||
fmt.Printf("%s=%#v\n", key, goenv.Get(key))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Show only one (or a few) environment variables.
|
|
||||||
for i := 0; i < flag.NArg(); i++ {
|
|
||||||
fmt.Println(goenv.Get(flag.Arg(i)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ func SetPriority(irq uint32, priority uint32) {
|
|||||||
func DisableInterrupts() uintptr {
|
func DisableInterrupts() uintptr {
|
||||||
return AsmFull(`
|
return AsmFull(`
|
||||||
mrs {}, PRIMASK
|
mrs {}, PRIMASK
|
||||||
cpsid if
|
cpsid i
|
||||||
`, nil)
|
`, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
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
|
||||||
@@ -19,3 +19,19 @@ func Asm(asm string)
|
|||||||
// You can use {} in the asm string (which expands to a register) to set the
|
// You can use {} in the asm string (which expands to a register) to set the
|
||||||
// return value.
|
// return value.
|
||||||
func AsmFull(asm string, regs map[string]interface{}) uintptr
|
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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,16 +5,14 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// This example assumes that the button is connected to pin 8. Change the value
|
|
||||||
// below to use a different pin.
|
|
||||||
const (
|
const (
|
||||||
led = machine.LED
|
led = machine.LED
|
||||||
button = machine.Pin(8)
|
button = machine.BUTTON
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
||||||
button.Configure(machine.PinConfig{Mode: machine.PinInput})
|
button.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
|
||||||
|
|
||||||
for {
|
for {
|
||||||
if button.Get() {
|
if button.Get() {
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// +build circuitplay_express
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "machine"
|
||||||
|
|
||||||
|
const (
|
||||||
|
buttonMode = machine.PinInputPulldown
|
||||||
|
buttonPinChange = machine.PinFalling
|
||||||
|
)
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// +build pca10040
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "machine"
|
||||||
|
|
||||||
|
const (
|
||||||
|
buttonMode = machine.PinInputPullup
|
||||||
|
buttonPinChange = machine.PinRising
|
||||||
|
)
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// +build wioterminal
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "machine"
|
||||||
|
|
||||||
|
const (
|
||||||
|
buttonMode = machine.PinInput
|
||||||
|
buttonPinChange = machine.PinFalling
|
||||||
|
)
|
||||||
+16
-6
@@ -8,9 +8,9 @@ import (
|
|||||||
// This example assumes that an RGB LED is connected to pins 3, 5 and 6 on an Arduino.
|
// 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.
|
// Change the values below to use different pins.
|
||||||
const (
|
const (
|
||||||
redPin = 3
|
redPin = machine.D3
|
||||||
greenPin = 5
|
greenPin = machine.D5
|
||||||
bluePin = 6
|
bluePin = machine.D6
|
||||||
)
|
)
|
||||||
|
|
||||||
// cycleColor is just a placeholder until math/rand or some equivalent is working.
|
// cycleColor is just a placeholder until math/rand or some equivalent is working.
|
||||||
@@ -28,13 +28,16 @@ func main() {
|
|||||||
machine.InitPWM()
|
machine.InitPWM()
|
||||||
|
|
||||||
red := machine.PWM{redPin}
|
red := machine.PWM{redPin}
|
||||||
red.Configure()
|
err := red.Configure()
|
||||||
|
checkError(err, "failed to configure red pin")
|
||||||
|
|
||||||
green := machine.PWM{greenPin}
|
green := machine.PWM{greenPin}
|
||||||
green.Configure()
|
err = green.Configure()
|
||||||
|
checkError(err, "failed to configure green pin")
|
||||||
|
|
||||||
blue := machine.PWM{bluePin}
|
blue := machine.PWM{bluePin}
|
||||||
blue.Configure()
|
err = blue.Configure()
|
||||||
|
checkError(err, "failed to configure blue pin")
|
||||||
|
|
||||||
var rc uint8
|
var rc uint8
|
||||||
var gc uint8 = 20
|
var gc uint8 = 20
|
||||||
@@ -52,3 +55,10 @@ func main() {
|
|||||||
time.Sleep(time.Millisecond * 500)
|
time.Sleep(time.Millisecond * 500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkError(err error, msg string) {
|
||||||
|
if err != nil {
|
||||||
|
print(msg, ": ", err.Error())
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,126 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
@@ -68,8 +68,8 @@ func (s *Stack) Pop() *Task {
|
|||||||
t := s.top
|
t := s.top
|
||||||
if t != nil {
|
if t != nil {
|
||||||
s.top = t.Next
|
s.top = t.Next
|
||||||
|
t.Next = nil
|
||||||
}
|
}
|
||||||
t.Next = nil
|
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ package task
|
|||||||
|
|
||||||
import "unsafe"
|
import "unsafe"
|
||||||
|
|
||||||
const stackSize = 256
|
const stackSize = 1024
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
// calleeSavedRegs is the list of registers that must be saved and restored when
|
||||||
// switching between tasks. Also see scheduler_avr.S that relies on the
|
// switching between tasks. Also see scheduler_avr.S that relies on the
|
||||||
|
|||||||
@@ -7,21 +7,39 @@ func CPUFrequency() uint32 {
|
|||||||
return 16000000
|
return 16000000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Digital pins, marked as plain numbers on the board.
|
||||||
|
const (
|
||||||
|
D0 = PD0 // RX
|
||||||
|
D1 = PD1 // TX
|
||||||
|
D2 = PD2
|
||||||
|
D3 = PD3
|
||||||
|
D4 = PD4
|
||||||
|
D5 = PD5
|
||||||
|
D6 = PD6
|
||||||
|
D7 = PD7
|
||||||
|
D8 = PB0
|
||||||
|
D9 = PB1
|
||||||
|
D10 = PB2
|
||||||
|
D11 = PB3
|
||||||
|
D12 = PB4
|
||||||
|
D13 = PB5
|
||||||
|
)
|
||||||
|
|
||||||
// LED on the Arduino
|
// LED on the Arduino
|
||||||
const LED Pin = 13
|
const LED Pin = D13
|
||||||
|
|
||||||
// ADC on the Arduino
|
// ADC on the Arduino
|
||||||
const (
|
const (
|
||||||
ADC0 Pin = 0
|
ADC0 Pin = PC0
|
||||||
ADC1 Pin = 1
|
ADC1 Pin = PC1
|
||||||
ADC2 Pin = 2
|
ADC2 Pin = PC2
|
||||||
ADC3 Pin = 3
|
ADC3 Pin = PC3
|
||||||
ADC4 Pin = 4 // Used by TWI for SDA
|
ADC4 Pin = PC4 // Used by TWI for SDA
|
||||||
ADC5 Pin = 5 // Used by TWI for SCL
|
ADC5 Pin = PC5 // Used by TWI for SCL
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN Pin = 1
|
UART_TX_PIN Pin = PD1
|
||||||
UART_RX_PIN Pin = 0
|
UART_RX_PIN Pin = PD0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,21 +7,39 @@ func CPUFrequency() uint32 {
|
|||||||
return 16000000
|
return 16000000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Digital pins.
|
||||||
|
const (
|
||||||
|
D0 = PD0 // RX0
|
||||||
|
D1 = PD1 // TX1
|
||||||
|
D2 = PD2
|
||||||
|
D3 = PD3
|
||||||
|
D4 = PD4
|
||||||
|
D5 = PD5
|
||||||
|
D6 = PD6
|
||||||
|
D7 = PD7
|
||||||
|
D8 = PB0
|
||||||
|
D9 = PB1
|
||||||
|
D10 = PB2
|
||||||
|
D11 = PB3
|
||||||
|
D12 = PB4
|
||||||
|
D13 = PB5
|
||||||
|
)
|
||||||
|
|
||||||
// LED on the Arduino
|
// LED on the Arduino
|
||||||
const LED Pin = 13
|
const LED Pin = D13
|
||||||
|
|
||||||
// ADC on the Arduino
|
// ADC on the Arduino
|
||||||
const (
|
const (
|
||||||
ADC0 Pin = 0
|
ADC0 Pin = PC0
|
||||||
ADC1 Pin = 1
|
ADC1 Pin = PC1
|
||||||
ADC2 Pin = 2
|
ADC2 Pin = PC2
|
||||||
ADC3 Pin = 3
|
ADC3 Pin = PC3
|
||||||
ADC4 Pin = 4 // Used by TWI for SDA
|
ADC4 Pin = PC4 // Used by TWI for SDA
|
||||||
ADC5 Pin = 5 // Used by TWI for SCL
|
ADC5 Pin = PC5 // Used by TWI for SCL
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN Pin = 1
|
UART_TX_PIN Pin = PD1
|
||||||
UART_RX_PIN Pin = 0
|
UART_RX_PIN Pin = PD0
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// +build avr,atmega328p arduino arduino_nano
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Note: start at port B because there is no port A.
|
||||||
|
portB Pin = iota * 8
|
||||||
|
portC
|
||||||
|
portD
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PB0 = portB + 0
|
||||||
|
PB1 = portB + 1
|
||||||
|
PB2 = portB + 2
|
||||||
|
PB3 = portB + 3
|
||||||
|
PB4 = portB + 4
|
||||||
|
PB5 = portB + 5
|
||||||
|
PB6 = portB + 6
|
||||||
|
PB7 = portB + 7
|
||||||
|
PC0 = portC + 0
|
||||||
|
PC1 = portC + 1
|
||||||
|
PC2 = portC + 2
|
||||||
|
PC3 = portC + 3
|
||||||
|
PC4 = portC + 4
|
||||||
|
PC5 = portC + 5
|
||||||
|
PC6 = portC + 6
|
||||||
|
PC7 = portC + 7
|
||||||
|
PD0 = portD + 0
|
||||||
|
PD1 = portD + 1
|
||||||
|
PD2 = portD + 2
|
||||||
|
PD3 = portD + 3
|
||||||
|
PD4 = portD + 4
|
||||||
|
PD5 = portD + 5
|
||||||
|
PD6 = portD + 6
|
||||||
|
PD7 = portD + 7
|
||||||
|
)
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
// +build sam,atsamd51,feather_m4
|
// +build feather_m4
|
||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
import "device/sam"
|
|
||||||
|
|
||||||
// used to reset into bootloader
|
// used to reset into bootloader
|
||||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||||
|
|
||||||
@@ -47,13 +45,11 @@ const (
|
|||||||
USBCDC_DP_PIN = PA25
|
USBCDC_DP_PIN = PA25
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART1 pins
|
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN = D1
|
UART_TX_PIN = D1
|
||||||
UART_RX_PIN = D0
|
UART_RX_PIN = D0
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART2 pins
|
|
||||||
const (
|
const (
|
||||||
UART2_TX_PIN = A4
|
UART2_TX_PIN = A4
|
||||||
UART2_RX_PIN = A5
|
UART2_RX_PIN = A5
|
||||||
@@ -65,14 +61,6 @@ const (
|
|||||||
SCL_PIN = D21 // SCL: SERCOM2/PAD[1]
|
SCL_PIN = D21 // SCL: SERCOM2/PAD[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C on the Feather M4.
|
|
||||||
var (
|
|
||||||
I2C0 = I2C{
|
|
||||||
Bus: sam.SERCOM2_I2CM,
|
|
||||||
SERCOM: 2,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = D25 // SCK: SERCOM1/PAD[1]
|
SPI0_SCK_PIN = D25 // SCK: SERCOM1/PAD[1]
|
||||||
@@ -80,14 +68,6 @@ const (
|
|||||||
SPI0_MISO_PIN = D23 // MISO: SERCOM1/PAD[2]
|
SPI0_MISO_PIN = D23 // MISO: SERCOM1/PAD[2]
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI on the Feather M4.
|
|
||||||
var (
|
|
||||||
SPI0 = SPI{
|
|
||||||
Bus: sam.SERCOM1_SPIM,
|
|
||||||
SERCOM: 1,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// USB CDC identifiers
|
// USB CDC identifiers
|
||||||
const (
|
const (
|
||||||
usb_STRING_PRODUCT = "Adafruit Feather M4"
|
usb_STRING_PRODUCT = "Adafruit Feather M4"
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// +build sam,atsamd51,feather_m4
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UART1 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM5_USART_INT,
|
||||||
|
SERCOM: 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
UART2 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM0_USART_INT,
|
||||||
|
SERCOM: 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM5_2, UART1.handleInterrupt)
|
||||||
|
UART2.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, UART2.handleInterrupt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// I2C on the Feather M4.
|
||||||
|
var (
|
||||||
|
I2C0 = I2C{
|
||||||
|
Bus: sam.SERCOM2_I2CM,
|
||||||
|
SERCOM: 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI on the Feather M4.
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{
|
||||||
|
Bus: sam.SERCOM1_SPIM,
|
||||||
|
SERCOM: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -37,8 +37,8 @@ const (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// TODO: figure out the pin numbers for these.
|
// TODO: figure out the pin numbers for these.
|
||||||
UART_TX_PIN = NoPin
|
UART_TX_PIN = D1
|
||||||
UART_RX_PIN = NoPin
|
UART_RX_PIN = D0
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
// +build sam,atsamd51,itsybitsy_m4
|
// +build itsybitsy_m4
|
||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
import "device/sam"
|
|
||||||
|
|
||||||
// used to reset into bootloader
|
// used to reset into bootloader
|
||||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||||
|
|
||||||
@@ -51,30 +49,17 @@ const (
|
|||||||
UART_RX_PIN = D0
|
UART_RX_PIN = D0
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART1 var is on SERCOM3, defined in atsamd51.go
|
|
||||||
|
|
||||||
// UART2 pins
|
|
||||||
const (
|
const (
|
||||||
UART2_TX_PIN = A4
|
UART2_TX_PIN = A4
|
||||||
UART2_RX_PIN = D2
|
UART2_RX_PIN = D2
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART2 var is on SERCOM0, defined in atsamd51.go
|
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = PA12 // SDA: SERCOM2/PAD[0]
|
SDA_PIN = PA12 // SDA: SERCOM2/PAD[0]
|
||||||
SCL_PIN = PA13 // SCL: SERCOM2/PAD[1]
|
SCL_PIN = PA13 // SCL: SERCOM2/PAD[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C on the ItsyBitsy M4.
|
|
||||||
var (
|
|
||||||
I2C0 = I2C{
|
|
||||||
Bus: sam.SERCOM2_I2CM,
|
|
||||||
SERCOM: 2,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = PA01 // SCK: SERCOM1/PAD[1]
|
SPI0_SCK_PIN = PA01 // SCK: SERCOM1/PAD[1]
|
||||||
@@ -82,14 +67,6 @@ const (
|
|||||||
SPI0_MISO_PIN = PB23 // MISO: SERCOM1/PAD[3]
|
SPI0_MISO_PIN = PB23 // MISO: SERCOM1/PAD[3]
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI on the ItsyBitsy M4.
|
|
||||||
var (
|
|
||||||
SPI0 = SPI{
|
|
||||||
Bus: sam.SERCOM1_SPIM,
|
|
||||||
SERCOM: 1,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// USB CDC identifiers
|
// USB CDC identifiers
|
||||||
const (
|
const (
|
||||||
usb_STRING_PRODUCT = "Adafruit ItsyBitsy M4"
|
usb_STRING_PRODUCT = "Adafruit ItsyBitsy M4"
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// +build sam,atsamd51,itsybitsy_m4
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UART1 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM3_USART_INT,
|
||||||
|
SERCOM: 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
UART2 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM0_USART_INT,
|
||||||
|
SERCOM: 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM3_2, UART1.handleInterrupt)
|
||||||
|
UART2.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, UART2.handleInterrupt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// I2C on the ItsyBitsy M4.
|
||||||
|
var (
|
||||||
|
I2C0 = I2C{
|
||||||
|
Bus: sam.SERCOM2_I2CM,
|
||||||
|
SERCOM: 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI on the ItsyBitsy M4.
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{
|
||||||
|
Bus: sam.SERCOM1_SPIM,
|
||||||
|
SERCOM: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
// +build sam,atsamd51,metro_m4_airlift
|
// +build metro_m4_airlift
|
||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
import "device/sam"
|
|
||||||
|
|
||||||
// used to reset into bootloader
|
// used to reset into bootloader
|
||||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||||
|
|
||||||
@@ -53,7 +51,10 @@ const (
|
|||||||
UART_RX_PIN = D0
|
UART_RX_PIN = D0
|
||||||
)
|
)
|
||||||
|
|
||||||
// Note: UART1 is on SERCOM3, defined in machine_atsamd51.go
|
const (
|
||||||
|
UART2_TX_PIN = PA04
|
||||||
|
UART2_RX_PIN = PA07
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
NINA_CS = PA15
|
NINA_CS = PA15
|
||||||
@@ -66,23 +67,12 @@ const (
|
|||||||
NINA_RTS = PB23
|
NINA_RTS = PB23
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART2 is on SERCOM0, defined in machine_atsamd51.go, and connects to the
|
|
||||||
// onboard ESP32-WROOM chip.
|
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = PB02 // SDA: SERCOM5/PAD[0]
|
SDA_PIN = PB02 // SDA: SERCOM5/PAD[0]
|
||||||
SCL_PIN = PB03 // SCL: SERCOM5/PAD[1]
|
SCL_PIN = PB03 // SCL: SERCOM5/PAD[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C on the Metro M4.
|
|
||||||
var (
|
|
||||||
I2C0 = I2C{
|
|
||||||
Bus: sam.SERCOM5_I2CM,
|
|
||||||
SERCOM: 5,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = PA13 // SCK: SERCOM2/PAD[1]
|
SPI0_SCK_PIN = PA13 // SCK: SERCOM2/PAD[1]
|
||||||
@@ -94,29 +84,12 @@ const (
|
|||||||
NINA_SCK = SPI0_SCK_PIN
|
NINA_SCK = SPI0_SCK_PIN
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI on the Metro M4.
|
|
||||||
var (
|
|
||||||
SPI0 = SPI{
|
|
||||||
Bus: sam.SERCOM2_SPIM,
|
|
||||||
SERCOM: 2,
|
|
||||||
}
|
|
||||||
NINA_SPI = SPI0
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SPI1_SCK_PIN = D12 // MISO: SERCOM1/PAD[1]
|
SPI1_SCK_PIN = D12 // MISO: SERCOM1/PAD[1]
|
||||||
SPI1_MOSI_PIN = D11 // MOSI: SERCOM1/PAD[3]
|
SPI1_MOSI_PIN = D11 // MOSI: SERCOM1/PAD[3]
|
||||||
SPI1_MISO_PIN = D13 // SCK: SERCOM1/PAD[0]
|
SPI1_MISO_PIN = D13 // SCK: SERCOM1/PAD[0]
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI1 on the Metro M4 on pins 11,12,13
|
|
||||||
var (
|
|
||||||
SPI1 = SPI{
|
|
||||||
Bus: sam.SERCOM1_SPIM,
|
|
||||||
SERCOM: 1,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// USB CDC identifiers
|
// USB CDC identifiers
|
||||||
const (
|
const (
|
||||||
usb_STRING_PRODUCT = "Adafruit Metro M4 Airlift Lite"
|
usb_STRING_PRODUCT = "Adafruit Metro M4 Airlift Lite"
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// +build sam,atsamd51,metro_m4_airlift
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UART1 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM3_USART_INT,
|
||||||
|
SERCOM: 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
UART2 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM0_USART_INT,
|
||||||
|
SERCOM: 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM3_2, UART1.handleInterrupt)
|
||||||
|
UART2.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, UART2.handleInterrupt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// I2C on the Metro M4.
|
||||||
|
var (
|
||||||
|
I2C0 = I2C{
|
||||||
|
Bus: sam.SERCOM5_I2CM,
|
||||||
|
SERCOM: 5,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI on the Metro M4.
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{
|
||||||
|
Bus: sam.SERCOM2_SPIM,
|
||||||
|
SERCOM: 2,
|
||||||
|
}
|
||||||
|
NINA_SPI = SPI0
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI1 on the Metro M4 on pins 11,12,13
|
||||||
|
var (
|
||||||
|
SPI1 = SPI{
|
||||||
|
Bus: sam.SERCOM1_SPIM,
|
||||||
|
SERCOM: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
// +build sam,atsamd51,pybadge
|
// +build pybadge
|
||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
import "device/sam"
|
|
||||||
|
|
||||||
// used to reset into bootloader
|
// used to reset into bootloader
|
||||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||||
|
|
||||||
@@ -80,30 +78,17 @@ const (
|
|||||||
UART_RX_PIN = D0
|
UART_RX_PIN = D0
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART1 var is on SERCOM3, defined in atsamd51.go
|
|
||||||
|
|
||||||
// UART2 pins
|
|
||||||
const (
|
const (
|
||||||
UART2_TX_PIN = A4
|
UART2_TX_PIN = A4
|
||||||
UART2_RX_PIN = A5
|
UART2_RX_PIN = A5
|
||||||
)
|
)
|
||||||
|
|
||||||
// UART2 var is on SERCOM0, defined in atsamd51.go
|
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = PA12 // SDA: SERCOM2/PAD[0]
|
SDA_PIN = PA12 // SDA: SERCOM2/PAD[0]
|
||||||
SCL_PIN = PA13 // SCL: SERCOM2/PAD[1]
|
SCL_PIN = PA13 // SCL: SERCOM2/PAD[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C on the ItsyBitsy M4.
|
|
||||||
var (
|
|
||||||
I2C0 = I2C{
|
|
||||||
Bus: sam.SERCOM2_I2CM,
|
|
||||||
SERCOM: 2,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = PA17 // SCK: SERCOM1/PAD[1]
|
SPI0_SCK_PIN = PA17 // SCK: SERCOM1/PAD[1]
|
||||||
@@ -111,14 +96,6 @@ const (
|
|||||||
SPI0_MISO_PIN = PB22 // MISO: SERCOM1/PAD[2]
|
SPI0_MISO_PIN = PB22 // MISO: SERCOM1/PAD[2]
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI on the PyBadge.
|
|
||||||
var (
|
|
||||||
SPI0 = SPI{
|
|
||||||
Bus: sam.SERCOM1_SPIM,
|
|
||||||
SERCOM: 1,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// TFT SPI pins
|
// TFT SPI pins
|
||||||
const (
|
const (
|
||||||
SPI1_SCK_PIN = PB13 // SCK: SERCOM4/PAD[1]
|
SPI1_SCK_PIN = PB13 // SCK: SERCOM4/PAD[1]
|
||||||
@@ -126,14 +103,6 @@ const (
|
|||||||
SPI1_MISO_PIN = NoPin
|
SPI1_MISO_PIN = NoPin
|
||||||
)
|
)
|
||||||
|
|
||||||
// TFT SPI on the PyBadge.
|
|
||||||
var (
|
|
||||||
SPI1 = SPI{
|
|
||||||
Bus: sam.SERCOM4_SPIM,
|
|
||||||
SERCOM: 4,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// USB CDC identifiers
|
// USB CDC identifiers
|
||||||
const (
|
const (
|
||||||
usb_STRING_PRODUCT = "Adafruit pyBadge M4"
|
usb_STRING_PRODUCT = "Adafruit pyBadge M4"
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
// +build sam,atsamd51,pybadge
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UART1 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM5_USART_INT,
|
||||||
|
SERCOM: 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
UART2 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM0_USART_INT,
|
||||||
|
SERCOM: 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM5_2, UART1.handleInterrupt)
|
||||||
|
UART2.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, UART2.handleInterrupt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// I2C on the ItsyBitsy M4.
|
||||||
|
var (
|
||||||
|
I2C0 = I2C{
|
||||||
|
Bus: sam.SERCOM2_I2CM,
|
||||||
|
SERCOM: 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI on the PyBadge.
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{
|
||||||
|
Bus: sam.SERCOM1_SPIM,
|
||||||
|
SERCOM: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// TFT SPI on the PyBadge.
|
||||||
|
var (
|
||||||
|
SPI1 = SPI{
|
||||||
|
Bus: sam.SERCOM4_SPIM,
|
||||||
|
SERCOM: 4,
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
// +build sam,atsamd51,pygamer
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import "device/sam"
|
||||||
|
|
||||||
|
// used to reset into bootloader
|
||||||
|
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||||
|
|
||||||
|
// GPIO Pins
|
||||||
|
const (
|
||||||
|
D0 = PB17 // UART0 RX/PWM available
|
||||||
|
D1 = PB16 // UART0 TX/PWM available
|
||||||
|
D2 = PB03
|
||||||
|
D3 = PB02
|
||||||
|
D4 = PA14 // PWM available
|
||||||
|
D5 = PA16 // PWM available
|
||||||
|
D6 = PA18 // PWM available
|
||||||
|
D7 = PB14 // CS for microSD card slot
|
||||||
|
D8 = PA15 // built-in neopixel
|
||||||
|
D9 = PA19 // PWM available
|
||||||
|
D10 = PA20 // can be used for PWM or UART1 TX
|
||||||
|
D11 = PA21 // can be used for PWM or UART1 RX
|
||||||
|
D12 = PA22 // PWM available
|
||||||
|
D13 = PA23 // PWM available
|
||||||
|
)
|
||||||
|
|
||||||
|
// Analog pins
|
||||||
|
const (
|
||||||
|
A0 = PA02 // ADC/AIN[0]
|
||||||
|
A1 = PA05 // ADC/AIN[2]
|
||||||
|
A2 = PB08 // ADC/AIN[3]
|
||||||
|
A3 = PB09 // ADC/AIN[4]
|
||||||
|
A4 = PA04 // ADC/AIN[5]
|
||||||
|
A5 = PA06 // ADC/AIN[6]
|
||||||
|
A6 = PB01 // ADC/AIN[12]/VMEAS
|
||||||
|
A7 = PB04 // ADC/AIN[6]/LIGHT
|
||||||
|
A8 = D2 // ADC/AIN[14]
|
||||||
|
A9 = D3 // ADC/AIN[15]
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LED = D13
|
||||||
|
NEOPIXELS = D8
|
||||||
|
|
||||||
|
SD_CS = D7
|
||||||
|
|
||||||
|
LIGHTSENSOR = A7
|
||||||
|
|
||||||
|
BUTTON_LATCH = PB00
|
||||||
|
BUTTON_OUT = PB30
|
||||||
|
BUTTON_CLK = PB31
|
||||||
|
|
||||||
|
JOYY = PB06
|
||||||
|
JOYX = PB07
|
||||||
|
|
||||||
|
TFT_DC = PB05
|
||||||
|
TFT_CS = PB12
|
||||||
|
TFT_RST = PA00
|
||||||
|
TFT_LITE = PA01
|
||||||
|
|
||||||
|
SPEAKER_ENABLE = PA27
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
BUTTON_SELECT_MASK = 16
|
||||||
|
BUTTON_START_MASK = 32
|
||||||
|
BUTTON_A_MASK = 64
|
||||||
|
BUTTON_B_MASK = 128
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART0 aka USBCDC pins
|
||||||
|
const (
|
||||||
|
USBCDC_DM_PIN = PA24
|
||||||
|
USBCDC_DP_PIN = PA25
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART1 pins
|
||||||
|
const (
|
||||||
|
UART_TX_PIN = D1
|
||||||
|
UART_RX_PIN = D0
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART1 var is on SERCOM3, defined in atsamd51.go
|
||||||
|
|
||||||
|
// UART2 pins
|
||||||
|
const (
|
||||||
|
UART2_TX_PIN = A4
|
||||||
|
UART2_RX_PIN = A5
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART2 var is on SERCOM0, defined in atsamd51.go
|
||||||
|
|
||||||
|
// I2C pins
|
||||||
|
const (
|
||||||
|
SDA_PIN = PA12 // SDA: SERCOM2/PAD[0]
|
||||||
|
SCL_PIN = PA13 // SCL: SERCOM2/PAD[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C on the PyGamer.
|
||||||
|
var (
|
||||||
|
I2C0 = I2C{
|
||||||
|
Bus: sam.SERCOM2_I2CM,
|
||||||
|
SERCOM: 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
const (
|
||||||
|
SPI0_SCK_PIN = PA17 // SCK: SERCOM1/PAD[1]
|
||||||
|
SPI0_MOSI_PIN = PB23 // MOSI: SERCOM1/PAD[3]
|
||||||
|
SPI0_MISO_PIN = PB22 // MISO: SERCOM1/PAD[2]
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI on the PyGamer.
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{
|
||||||
|
Bus: sam.SERCOM1_SPIM,
|
||||||
|
SERCOM: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// TFT SPI pins
|
||||||
|
const (
|
||||||
|
SPI1_SCK_PIN = PB13 // SCK: SERCOM4/PAD[1]
|
||||||
|
SPI1_MOSI_PIN = PB15 // MOSI: SERCOM4/PAD[3]
|
||||||
|
SPI1_MISO_PIN = NoPin
|
||||||
|
)
|
||||||
|
|
||||||
|
// TFT SPI on the PyGamer.
|
||||||
|
var (
|
||||||
|
SPI1 = SPI{
|
||||||
|
Bus: sam.SERCOM4_SPIM,
|
||||||
|
SERCOM: 4,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// USB CDC identifiers
|
||||||
|
const (
|
||||||
|
usb_STRING_PRODUCT = "Adafruit pyGamer M4"
|
||||||
|
usb_STRING_MANUFACTURER = "Adafruit"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
usb_VID uint16 = 0x239A
|
||||||
|
usb_PID uint16 = 0x8033
|
||||||
|
)
|
||||||
@@ -1,11 +1,7 @@
|
|||||||
// +build sam,atsamd51,pyportal
|
// +build pyportal
|
||||||
|
|
||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
|
||||||
"device/sam"
|
|
||||||
)
|
|
||||||
|
|
||||||
// used to reset into bootloader
|
// used to reset into bootloader
|
||||||
const RESET_MAGIC_VALUE = 0xf01669ef
|
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||||
|
|
||||||
@@ -104,10 +100,10 @@ const (
|
|||||||
USBCDC_DP_PIN = PA25
|
USBCDC_DP_PIN = PA25
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: add configuration for UART on SERCOM4 that is connected to TX/RX of ESP32
|
// UART1 aka NINA_TX/NINA_RX
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN = NoPin
|
UART_TX_PIN = D1
|
||||||
UART_RX_PIN = NoPin
|
UART_RX_PIN = D0
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
@@ -116,14 +112,6 @@ const (
|
|||||||
SCL_PIN = PB03 // SCL: SERCOM2/PAD[1]
|
SCL_PIN = PB03 // SCL: SERCOM2/PAD[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C on the PyPortal.
|
|
||||||
var (
|
|
||||||
I2C0 = I2C{
|
|
||||||
Bus: sam.SERCOM5_I2CM,
|
|
||||||
SERCOM: 5,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = PA13 // SCK: SERCOM1/PAD[1]
|
SPI0_SCK_PIN = PA13 // SCK: SERCOM1/PAD[1]
|
||||||
@@ -135,15 +123,6 @@ const (
|
|||||||
NINA_SCK = SPI0_SCK_PIN
|
NINA_SCK = SPI0_SCK_PIN
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI on the PyPortal.
|
|
||||||
var (
|
|
||||||
SPI0 = SPI{
|
|
||||||
Bus: sam.SERCOM2_SPIM,
|
|
||||||
SERCOM: 2,
|
|
||||||
}
|
|
||||||
NINA_SPI = SPI0
|
|
||||||
)
|
|
||||||
|
|
||||||
// USB CDC identifiers
|
// USB CDC identifiers
|
||||||
const (
|
const (
|
||||||
usb_STRING_PRODUCT = "Adafruit PyPortal M4"
|
usb_STRING_PRODUCT = "Adafruit PyPortal M4"
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// +build sam,atsamd51,pyportal
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UART1 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM4_USART_INT,
|
||||||
|
SERCOM: 4,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM4_2, UART1.handleInterrupt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// I2C on the PyPortal.
|
||||||
|
var (
|
||||||
|
I2C0 = I2C{
|
||||||
|
Bus: sam.SERCOM5_I2CM,
|
||||||
|
SERCOM: 5,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI on the PyPortal.
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{
|
||||||
|
Bus: sam.SERCOM2_SPIM,
|
||||||
|
SERCOM: 2,
|
||||||
|
}
|
||||||
|
NINA_SPI = SPI0
|
||||||
|
)
|
||||||
@@ -0,0 +1,392 @@
|
|||||||
|
// +build wioterminal
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
// used to reset into bootloader
|
||||||
|
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||||
|
|
||||||
|
const (
|
||||||
|
ADC0 = A0
|
||||||
|
ADC1 = A1
|
||||||
|
ADC2 = A2
|
||||||
|
ADC3 = A3
|
||||||
|
ADC4 = A4
|
||||||
|
ADC5 = A5
|
||||||
|
ADC6 = A6
|
||||||
|
ADC7 = A7
|
||||||
|
ADC8 = A8
|
||||||
|
|
||||||
|
LED = PIN_LED
|
||||||
|
BUTTON = BUTTON_1
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// https://github.com/Seeed-Studio/ArduinoCore-samd/blob/master/variants/wio_terminal/variant.h
|
||||||
|
|
||||||
|
// LEDs
|
||||||
|
PIN_LED_13 = PA15
|
||||||
|
PIN_LED_RXL = PA15
|
||||||
|
PIN_LED_TXL = PA15
|
||||||
|
PIN_LED = PIN_LED_13
|
||||||
|
PIN_LED2 = PIN_LED_RXL
|
||||||
|
PIN_LED3 = PIN_LED_TXL
|
||||||
|
LED_BUILTIN = PIN_LED_13
|
||||||
|
PIN_NEOPIXEL = PA15
|
||||||
|
|
||||||
|
//Digital PINs
|
||||||
|
D0 = PB08
|
||||||
|
D1 = PB09
|
||||||
|
D2 = PA07
|
||||||
|
D3 = PB04
|
||||||
|
D4 = PB05
|
||||||
|
D5 = PB06
|
||||||
|
D6 = PA04
|
||||||
|
D7 = PB07
|
||||||
|
D8 = PA06
|
||||||
|
|
||||||
|
//Analog PINs
|
||||||
|
A0 = PB08 // ADC/AIN[0]
|
||||||
|
A1 = PB09 // ADC/AIN[2]
|
||||||
|
A2 = PA07 // ADC/AIN[3]
|
||||||
|
A3 = PB04 // ADC/AIN[4]
|
||||||
|
A4 = PB05 // ADC/AIN[5]
|
||||||
|
A5 = PB06 // ADC/AIN[10]
|
||||||
|
A6 = PA04 // ADC/AIN[10]
|
||||||
|
A7 = PB07 // ADC/AIN[10]
|
||||||
|
A8 = PA06 // ADC/AIN[10]
|
||||||
|
|
||||||
|
// 3.3V || 5V
|
||||||
|
// BCM2 || 5V
|
||||||
|
// BCM3 || GND
|
||||||
|
// BCM4 || BCM14
|
||||||
|
// GND || BCM15
|
||||||
|
// BCM17 || BCM18
|
||||||
|
// BCM27 || GND
|
||||||
|
// BCM22 || BCM23
|
||||||
|
// GND || BCM24
|
||||||
|
// BCM10 || GND
|
||||||
|
// BCM9 || BCM25
|
||||||
|
// BCM11 || BCM8
|
||||||
|
// GND || BCM7
|
||||||
|
// BCM0 || BCM1
|
||||||
|
// BCM5 || GND
|
||||||
|
// BCM6 || BCM12
|
||||||
|
// BCM13 || GND
|
||||||
|
// BCM19 || BCM16
|
||||||
|
// BCM26 || BCM20
|
||||||
|
// GND || BCM21
|
||||||
|
|
||||||
|
//PIN DEFINE FOR RPI
|
||||||
|
BCM0 = PA13 // I2C Wire1
|
||||||
|
BCM1 = PA12 // I2C Wire1
|
||||||
|
BCM2 = PA17 // I2C Wire2
|
||||||
|
BCM3 = PA16 // I2C Wire2
|
||||||
|
BCM4 = PB14 // GCLK
|
||||||
|
BCM5 = PB12 // GCLK
|
||||||
|
BCM6 = PB13 // GCLK
|
||||||
|
BCM7 = PA05 // DAC1
|
||||||
|
BCM8 = PB01 // SPI SS
|
||||||
|
BCM9 = PB00 // SPI MISO
|
||||||
|
BCM10 = PB02 // SPI MOSI
|
||||||
|
BCM11 = PB03 // SPI SCK
|
||||||
|
BCM12 = PB06
|
||||||
|
BCM13 = PA07
|
||||||
|
BCM14 = PB27 // UART Serial1
|
||||||
|
BCM15 = PB26 // UART Serial1
|
||||||
|
BCM16 = PB07
|
||||||
|
BCM17 = PA02 // DAC0
|
||||||
|
BCM18 = PB28 // FPC Digital & AD pins
|
||||||
|
BCM19 = PA20 // WIO_IR
|
||||||
|
BCM20 = PA21 // I2S SDO
|
||||||
|
BCM21 = PA22 // I2S SDI
|
||||||
|
BCM22 = PB09
|
||||||
|
BCM23 = PA07
|
||||||
|
BCM24 = PB04
|
||||||
|
BCM25 = PB05
|
||||||
|
BCM26 = PA06
|
||||||
|
BCM27 = PB08
|
||||||
|
|
||||||
|
// FPC NEW DEFINE
|
||||||
|
FPC1 = PB28 // FPC Digital & AD pins
|
||||||
|
FPC2 = PB17
|
||||||
|
FPC3 = PB29
|
||||||
|
FPC4 = PA14
|
||||||
|
FPC5 = PC01
|
||||||
|
FPC6 = PC02
|
||||||
|
FPC7 = PC03
|
||||||
|
FPC8 = PC04
|
||||||
|
FPC9 = PC31
|
||||||
|
FPC10 = PD00
|
||||||
|
|
||||||
|
// RPI Analog RPIs
|
||||||
|
RPI_A0 = PB08
|
||||||
|
RPI_A1 = PB09
|
||||||
|
RPI_A2 = PA07
|
||||||
|
RPI_A3 = PB04
|
||||||
|
RPI_A4 = PB05
|
||||||
|
RPI_A5 = PB06
|
||||||
|
RPI_A6 = PA04
|
||||||
|
RPI_A7 = PB07
|
||||||
|
RPI_A8 = PA06
|
||||||
|
|
||||||
|
PIN_DAC0 = PA02
|
||||||
|
PIN_DAC1 = PA05
|
||||||
|
|
||||||
|
DAC0 = PIN_DAC0
|
||||||
|
DAC1 = PIN_DAC1
|
||||||
|
|
||||||
|
// FPO Analog RPIs
|
||||||
|
//FPC_A7 = FPC_D7
|
||||||
|
//FPC_A8 = FPC_D8
|
||||||
|
//FPC_A9 = FPC_D9
|
||||||
|
//FPC_A11 = FPC_D11
|
||||||
|
//FPC_A12 = FPC_D12
|
||||||
|
//FPC_A13 = FPC_D13
|
||||||
|
|
||||||
|
// USB
|
||||||
|
PIN_USB_DM = PA24
|
||||||
|
PIN_USB_DP = PA25
|
||||||
|
PIN_USB_HOST_ENABLE = PA27
|
||||||
|
|
||||||
|
// BUTTON
|
||||||
|
BUTTON_1 = PC26
|
||||||
|
BUTTON_2 = PC27
|
||||||
|
BUTTON_3 = PC28
|
||||||
|
WIO_KEY_A = PC26
|
||||||
|
WIO_KEY_B = PC27
|
||||||
|
WIO_KEY_C = PC28
|
||||||
|
|
||||||
|
// SWITCH
|
||||||
|
SWITCH_X = PD20
|
||||||
|
SWITCH_Y = PD12
|
||||||
|
SWITCH_Z = PD09
|
||||||
|
SWITCH_B = PD08
|
||||||
|
SWITCH_U = PD10
|
||||||
|
|
||||||
|
WIO_5S_UP = PD20
|
||||||
|
WIO_5S_LEFT = PD12
|
||||||
|
WIO_5S_RIGHT = PD09
|
||||||
|
WIO_5S_DOWN = PD08
|
||||||
|
WIO_5S_PRESS = PD10
|
||||||
|
|
||||||
|
// IRQ0 : RTL8720D
|
||||||
|
IRQ0 = PC20
|
||||||
|
|
||||||
|
// BUZZER_CTR
|
||||||
|
BUZZER_CTR = PD11
|
||||||
|
WIO_BUZZER = PD11
|
||||||
|
|
||||||
|
// MIC_INPUT
|
||||||
|
MIC_INPUT = PC30
|
||||||
|
WIO_MIC = PC30
|
||||||
|
|
||||||
|
// GCLK
|
||||||
|
GCLK0 = PB14
|
||||||
|
GCLK1 = PB12
|
||||||
|
GCLK2 = PB13
|
||||||
|
|
||||||
|
// Serial interfaces
|
||||||
|
// Serial1
|
||||||
|
PIN_SERIAL1_RX = PB27
|
||||||
|
PIN_SERIAL1_TX = PB26
|
||||||
|
|
||||||
|
// Serial2 : RTL8720D
|
||||||
|
PIN_SERIAL2_RX = PC23
|
||||||
|
PIN_SERIAL2_TX = PC22
|
||||||
|
|
||||||
|
// Wire Interfaces
|
||||||
|
// I2C Wire2
|
||||||
|
// I2C1
|
||||||
|
PIN_WIRE_SDA = PA17
|
||||||
|
PIN_WIRE_SCL = PA16
|
||||||
|
SDA = PIN_WIRE_SDA
|
||||||
|
SCL = PIN_WIRE_SCL
|
||||||
|
|
||||||
|
// I2C Wire1
|
||||||
|
// I2C0 : LIS3DHTR and ATECC608
|
||||||
|
PIN_WIRE1_SDA = PA13
|
||||||
|
PIN_WIRE1_SCL = PA12
|
||||||
|
|
||||||
|
SDA1 = PIN_WIRE1_SDA
|
||||||
|
SCL1 = PIN_WIRE1_SCL
|
||||||
|
|
||||||
|
PIN_GYROSCOPE_WIRE_SDA = PIN_WIRE1_SDA
|
||||||
|
PIN_GYROSCOPE_WIRE_SCL = PIN_WIRE1_SCL
|
||||||
|
GYROSCOPE_INT1 = PC21
|
||||||
|
|
||||||
|
WIO_LIS3DH_SDA = PIN_WIRE1_SDA
|
||||||
|
WIO_LIS3DH_SCL = PIN_WIRE1_SCL
|
||||||
|
WIO_LIS3DH_INT = PC21
|
||||||
|
|
||||||
|
// SPI
|
||||||
|
PIN_SPI_MISO = PB00
|
||||||
|
PIN_SPI_MOSI = PB02
|
||||||
|
PIN_SPI_SCK = PB03
|
||||||
|
PIN_SPI_SS = PB01
|
||||||
|
|
||||||
|
SS = PIN_SPI_SS
|
||||||
|
MOSI = PIN_SPI_MOSI
|
||||||
|
MISO = PIN_SPI_MISO
|
||||||
|
SCK = PIN_SPI_SCK
|
||||||
|
|
||||||
|
// SPI1 RTL8720D_SPI
|
||||||
|
PIN_SPI1_MISO = PC24
|
||||||
|
PIN_SPI1_MOSI = PB24
|
||||||
|
PIN_SPI1_SCK = PB25
|
||||||
|
PIN_SPI1_SS = PC25
|
||||||
|
|
||||||
|
SS1 = PIN_SPI1_SS
|
||||||
|
MOSI1 = PIN_SPI1_MOSI
|
||||||
|
MISO1 = PIN_SPI1_MISO
|
||||||
|
SCK1 = PIN_SPI1_SCK
|
||||||
|
|
||||||
|
// SPI2 SD_SPI
|
||||||
|
PIN_SPI2_MISO = PC18
|
||||||
|
PIN_SPI2_MOSI = PC16
|
||||||
|
PIN_SPI2_SCK = PC17
|
||||||
|
PIN_SPI2_SS = PC19
|
||||||
|
|
||||||
|
SS2 = PIN_SPI2_SS
|
||||||
|
MOSI2 = PIN_SPI2_MOSI
|
||||||
|
MISO2 = PIN_SPI2_MISO
|
||||||
|
SCK2 = PIN_SPI2_SCK
|
||||||
|
|
||||||
|
// SPI3 LCD_SPI
|
||||||
|
PIN_SPI3_MISO = PB18
|
||||||
|
PIN_SPI3_MOSI = PB19
|
||||||
|
PIN_SPI3_SCK = PB20
|
||||||
|
PIN_SPI3_SS = PB21
|
||||||
|
|
||||||
|
SS3 = PIN_SPI3_SS
|
||||||
|
MOSI3 = PIN_SPI3_MOSI
|
||||||
|
MISO3 = PIN_SPI3_MISO
|
||||||
|
SCK3 = PIN_SPI3_SCK
|
||||||
|
|
||||||
|
// Needed for SD library
|
||||||
|
SDCARD_MISO_PIN = PIN_SPI2_MISO
|
||||||
|
SDCARD_MOSI_PIN = PIN_SPI2_MOSI
|
||||||
|
SDCARD_SCK_PIN = PIN_SPI2_SCK
|
||||||
|
SDCARD_SS_PIN = PIN_SPI2_SS
|
||||||
|
SDCARD_DET_PIN = PD21
|
||||||
|
|
||||||
|
LCD_MISO_PIN = PIN_SPI3_MISO
|
||||||
|
LCD_MOSI_PIN = PIN_SPI3_MOSI
|
||||||
|
LCD_SCK_PIN = PIN_SPI3_SCK
|
||||||
|
LCD_SS_PIN = PIN_SPI3_SS
|
||||||
|
LCD_DC = PC06
|
||||||
|
LCD_RESET = PC07
|
||||||
|
LCD_BACKLIGHT = PC05
|
||||||
|
|
||||||
|
// 4 WIRE LCD TOUCH
|
||||||
|
LCD_XL = PC10
|
||||||
|
LCD_YU = PC11
|
||||||
|
LCD_XR = PC12
|
||||||
|
LCD_YD = PC13
|
||||||
|
|
||||||
|
// Needed for RTL8720D
|
||||||
|
RTL8720D_MISO_PIN = PIN_SPI1_MISO
|
||||||
|
RTL8720D_MOSI_PIN = PIN_SPI1_MOSI
|
||||||
|
RTL8720D_SCK_PIN = PIN_SPI1_SCK
|
||||||
|
RTL8720D_SS_PIN = PIN_SPI1_SS
|
||||||
|
|
||||||
|
//QSPI Pins
|
||||||
|
PIN_QSPI_IO0 = PA08
|
||||||
|
PIN_QSPI_IO1 = PA09
|
||||||
|
PIN_QSPI_IO2 = PA10
|
||||||
|
PIN_QSPI_IO3 = PA11
|
||||||
|
PIN_QSPI_SCK = PB10
|
||||||
|
PIN_QSPI_CS = PB11
|
||||||
|
|
||||||
|
// I2S Interfaces
|
||||||
|
PIN_I2S_FS = PA20
|
||||||
|
PIN_I2S_SCK = PB16
|
||||||
|
PIN_I2S_SDO = PA22
|
||||||
|
PIN_I2S_SDI = PA21
|
||||||
|
|
||||||
|
I2S_LRCLK = PA20
|
||||||
|
I2S_BLCK = PB16
|
||||||
|
I2S_SDOUT = PA22
|
||||||
|
I2S_SDIN = PA21
|
||||||
|
|
||||||
|
// RTL8720D Interfaces
|
||||||
|
RTL8720D_CHIP_PU = PA18
|
||||||
|
RTL8720D_GPIO0 = PA19 // SYNC
|
||||||
|
|
||||||
|
// SWD
|
||||||
|
SWDCLK = PA30
|
||||||
|
SWDIO = PA31
|
||||||
|
SWO = PB30
|
||||||
|
|
||||||
|
// light sensor
|
||||||
|
WIO_LIGHT = PD01
|
||||||
|
|
||||||
|
// ir sensor
|
||||||
|
WIO_IR = PB31
|
||||||
|
|
||||||
|
// OUTPUT_CTR
|
||||||
|
OUTPUT_CTR_5V = PC14
|
||||||
|
OUTPUT_CTR_3V3 = PC15
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART0 aka USBCDC pins
|
||||||
|
const (
|
||||||
|
USBCDC_DM_PIN = PIN_USB_DM
|
||||||
|
USBCDC_DP_PIN = PIN_USB_DP
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART1 pins
|
||||||
|
const (
|
||||||
|
UART_TX_PIN = PIN_SERIAL1_TX
|
||||||
|
UART_RX_PIN = PIN_SERIAL1_RX
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART2 pins RTL8720D
|
||||||
|
const (
|
||||||
|
UART2_TX_PIN = PIN_SERIAL2_TX
|
||||||
|
UART2_RX_PIN = PIN_SERIAL2_RX
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C pins
|
||||||
|
const (
|
||||||
|
SDA0_PIN = PIN_WIRE_SDA // SDA: SERCOM3/PAD[0]
|
||||||
|
SCL0_PIN = PIN_WIRE_SCL // SCL: SERCOM3/PAD[1]
|
||||||
|
|
||||||
|
SDA1_PIN = PIN_WIRE1_SDA // SDA: SERCOM4/PAD[0]
|
||||||
|
SCL1_PIN = PIN_WIRE1_SCL // SCL: SERCOM4/PAD[1]
|
||||||
|
|
||||||
|
SDA_PIN = SDA0_PIN
|
||||||
|
SCL_PIN = SCL0_PIN
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
const (
|
||||||
|
SPI0_SCK_PIN = SCK // SCK: SERCOM5/PAD[1]
|
||||||
|
SPI0_MOSI_PIN = MOSI // MOSI: SERCOM5/PAD[0]
|
||||||
|
SPI0_MISO_PIN = MISO // MISO: SERCOM5/PAD[2]
|
||||||
|
|
||||||
|
// RTL8720D
|
||||||
|
SPI1_SCK_PIN = SCK1 // SCK: SERCOM0/PAD[1]
|
||||||
|
SPI1_MOSI_PIN = MOSI1 // MOSI: SERCOM0/PAD[0]
|
||||||
|
SPI1_MISO_PIN = MISO1 // MISO: SERCOM0/PAD[2]
|
||||||
|
|
||||||
|
// SD
|
||||||
|
SPI2_SCK_PIN = SCK2 // SCK: SERCOM6/PAD[1]
|
||||||
|
SPI2_MOSI_PIN = MOSI2 // MOSI: SERCOM6/PAD[0]
|
||||||
|
SPI2_MISO_PIN = MISO2 // MISO: SERCOM6/PAD[2]
|
||||||
|
|
||||||
|
// LCD
|
||||||
|
SPI3_SCK_PIN = SCK3 // SCK: SERCOM7/PAD[1]
|
||||||
|
SPI3_MOSI_PIN = MOSI3 // MOSI: SERCOM7/PAD[3]
|
||||||
|
SPI3_MISO_PIN = MISO3 // MISO: SERCOM7/PAD[2]
|
||||||
|
)
|
||||||
|
|
||||||
|
// USB CDC identifiers
|
||||||
|
const (
|
||||||
|
usb_STRING_PRODUCT = "Seeed Wio Terminal"
|
||||||
|
usb_STRING_MANUFACTURER = "Seeed"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
usb_VID uint16 = 0x2886
|
||||||
|
usb_PID uint16 = 0x802D
|
||||||
|
)
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
// +build sam,atsamd51,wioterminal
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
UART1 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM2_USART_INT,
|
||||||
|
SERCOM: 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
// RTL8720D
|
||||||
|
UART2 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM1_USART_INT,
|
||||||
|
SERCOM: 1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM2_2, UART1.handleInterrupt)
|
||||||
|
UART2.Interrupt = interrupt.New(sam.IRQ_SERCOM1_2, UART2.handleInterrupt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// I2C on the Wio Terminal
|
||||||
|
var (
|
||||||
|
I2C0 = I2C{
|
||||||
|
Bus: sam.SERCOM4_I2CM,
|
||||||
|
SERCOM: 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
I2C1 = I2C{
|
||||||
|
Bus: sam.SERCOM4_I2CM,
|
||||||
|
SERCOM: 4,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI on the Wio Terminal
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{
|
||||||
|
Bus: sam.SERCOM5_SPIM,
|
||||||
|
SERCOM: 5,
|
||||||
|
}
|
||||||
|
|
||||||
|
// RTL8720D
|
||||||
|
SPI1 = SPI{
|
||||||
|
Bus: sam.SERCOM0_SPIM,
|
||||||
|
SERCOM: 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
// SD
|
||||||
|
SPI2 = SPI{
|
||||||
|
Bus: sam.SERCOM6_SPIM,
|
||||||
|
SERCOM: 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
// LCD
|
||||||
|
SPI3 = SPI{
|
||||||
|
Bus: sam.SERCOM7_SPIM,
|
||||||
|
SERCOM: 7,
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
// +build sam,atsamd21,xiao
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/sam"
|
||||||
|
"runtime/interrupt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// used to reset into bootloader
|
||||||
|
const RESET_MAGIC_VALUE = 0xf01669ef
|
||||||
|
|
||||||
|
// GPIO Pins
|
||||||
|
const (
|
||||||
|
D0 = PA02 // can be used for PWM or DAC
|
||||||
|
D1 = PA04 // PWM available
|
||||||
|
D2 = PA10 // PWM available
|
||||||
|
D3 = PA11 // PWM available
|
||||||
|
D4 = PA08 // can be used for PWM or I2C SDA
|
||||||
|
D5 = PA09 // can be used for PWM or I2C SCL
|
||||||
|
D6 = PB08 // can be used for PWM or UART1 TX
|
||||||
|
D7 = PB09 // can be used for PWM or UART1 RX
|
||||||
|
D8 = PA07 // can be used for PWM or SPI SCK
|
||||||
|
D9 = PA05 // can be used for PWM or SPI MISO
|
||||||
|
D10 = PA06 // can be used for PWM or SPI MOSI
|
||||||
|
)
|
||||||
|
|
||||||
|
// Analog pins
|
||||||
|
const (
|
||||||
|
A0 = PA02 // ADC/AIN[0]
|
||||||
|
A1 = PA04 // ADC/AIN[4]
|
||||||
|
A2 = PA10 // ADC/AIN[18]
|
||||||
|
A3 = PA11 // ADC/AIN[19]
|
||||||
|
A4 = PA08 // ADC/AIN[16]
|
||||||
|
A5 = PA09 // ADC/AIN[17]
|
||||||
|
A6 = PB08 // ADC/AIN[2]
|
||||||
|
A7 = PB09 // ADC/AIN[3]
|
||||||
|
A8 = PA07 // ADC/AIN[7]
|
||||||
|
A9 = PA05 // ADC/AIN[6]
|
||||||
|
A10 = PA06 // ADC/AIN[5]
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LED = PA17
|
||||||
|
LED_RXL = PA18
|
||||||
|
LED_TXL = PA19
|
||||||
|
LED2 = LED_RXL
|
||||||
|
LED3 = LED_TXL
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART0 aka USBCDC pins
|
||||||
|
const (
|
||||||
|
USBCDC_DM_PIN = PA24
|
||||||
|
USBCDC_DP_PIN = PA25
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART1 pins
|
||||||
|
const (
|
||||||
|
UART_TX_PIN = D6
|
||||||
|
UART_RX_PIN = D7
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART1 on the Xiao
|
||||||
|
var (
|
||||||
|
UART1 = UART{
|
||||||
|
Buffer: NewRingBuffer(),
|
||||||
|
Bus: sam.SERCOM4_USART,
|
||||||
|
SERCOM: 4,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM4, UART1.handleInterrupt)
|
||||||
|
}
|
||||||
|
|
||||||
|
// I2C pins
|
||||||
|
const (
|
||||||
|
SDA_PIN = PA08 // SDA: SERCOM2/PAD[0]
|
||||||
|
SCL_PIN = PA09 // SCL: SERCOM2/PAD[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C on the Xiao
|
||||||
|
var (
|
||||||
|
I2C0 = I2C{
|
||||||
|
Bus: sam.SERCOM2_I2CM,
|
||||||
|
SERCOM: 2,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
const (
|
||||||
|
SPI0_SCK_PIN = PA07 // SCK: SERCOM0/PAD[3]
|
||||||
|
SPI0_MOSI_PIN = PA06 // MOSI: SERCOM0/PAD[2]
|
||||||
|
SPI0_MISO_PIN = PA05 // MISO: SERCOM0/PAD[1]
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI on the Xiao
|
||||||
|
var (
|
||||||
|
SPI0 = SPI{
|
||||||
|
Bus: sam.SERCOM0_SPI,
|
||||||
|
SERCOM: 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2S pins
|
||||||
|
const (
|
||||||
|
I2S_SCK_PIN = PA10
|
||||||
|
I2S_SD_PIN = PA08
|
||||||
|
I2S_WS_PIN = NoPin // TODO: figure out what this is on Xiao
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2S on the Xiao
|
||||||
|
var (
|
||||||
|
I2S0 = I2S{Bus: sam.I2S}
|
||||||
|
)
|
||||||
|
|
||||||
|
// USB CDC identifiers
|
||||||
|
const (
|
||||||
|
usb_STRING_PRODUCT = "Seeed XIAO M0"
|
||||||
|
usb_STRING_MANUFACTURER = "Seeed"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
usb_VID uint16 = 0x2886
|
||||||
|
usb_PID uint16 = 0x802F
|
||||||
|
)
|
||||||
@@ -3,10 +3,11 @@ package machine
|
|||||||
import "errors"
|
import "errors"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrInvalidInputPin = errors.New("machine: invalid input pin")
|
ErrInvalidInputPin = errors.New("machine: invalid input pin")
|
||||||
ErrInvalidOutputPin = errors.New("machine: invalid output pin")
|
ErrInvalidOutputPin = errors.New("machine: invalid output pin")
|
||||||
ErrInvalidClockPin = errors.New("machine: invalid clock pin")
|
ErrInvalidClockPin = errors.New("machine: invalid clock pin")
|
||||||
ErrInvalidDataPin = errors.New("machine: invalid data pin")
|
ErrInvalidDataPin = errors.New("machine: invalid data pin")
|
||||||
|
ErrNoPinChangeChannel = errors.New("machine: no channel available for pin interrupt")
|
||||||
)
|
)
|
||||||
|
|
||||||
type PinConfig struct {
|
type PinConfig struct {
|
||||||
|
|||||||
@@ -7,72 +7,6 @@ import (
|
|||||||
"runtime/interrupt"
|
"runtime/interrupt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitPWM initializes the registers needed for PWM.
|
|
||||||
func InitPWM() {
|
|
||||||
// use waveform generation
|
|
||||||
avr.TCCR0A.SetBits(avr.TCCR0A_WGM00)
|
|
||||||
|
|
||||||
// set timer 0 prescale factor to 64
|
|
||||||
avr.TCCR0B.SetBits(avr.TCCR0B_CS01 | avr.TCCR0B_CS00)
|
|
||||||
|
|
||||||
// set timer 1 prescale factor to 64
|
|
||||||
avr.TCCR1B.SetBits(avr.TCCR1B_CS11)
|
|
||||||
|
|
||||||
// put timer 1 in 8-bit phase correct pwm mode
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_WGM10)
|
|
||||||
|
|
||||||
// set timer 2 prescale factor to 64
|
|
||||||
avr.TCCR2B.SetBits(avr.TCCR2B_CS22)
|
|
||||||
|
|
||||||
// configure timer 2 for phase correct pwm (8-bit)
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_WGM20)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure configures a PWM pin for output.
|
|
||||||
func (pwm PWM) Configure() {
|
|
||||||
if pwm.Pin < 8 {
|
|
||||||
avr.DDRD.SetBits(1 << uint8(pwm.Pin))
|
|
||||||
} else {
|
|
||||||
avr.DDRB.SetBits(1 << uint8(pwm.Pin-8))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set turns on the duty cycle for a PWM pin using the provided value. On the AVR this is normally a
|
|
||||||
// 8-bit value ranging from 0 to 255.
|
|
||||||
func (pwm PWM) Set(value uint16) {
|
|
||||||
value8 := uint8(value >> 8)
|
|
||||||
switch pwm.Pin {
|
|
||||||
case 3:
|
|
||||||
// connect pwm to pin on timer 2, channel B
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1)
|
|
||||||
avr.OCR2B.Set(value8) // set pwm duty
|
|
||||||
case 5:
|
|
||||||
// connect pwm to pin on timer 0, channel B
|
|
||||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
|
|
||||||
avr.OCR0B.Set(value8) // set pwm duty
|
|
||||||
case 6:
|
|
||||||
// connect pwm to pin on timer 0, channel A
|
|
||||||
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1)
|
|
||||||
avr.OCR0A.Set(value8) // set pwm duty
|
|
||||||
case 9:
|
|
||||||
// connect pwm to pin on timer 1, channel A
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1)
|
|
||||||
// this is a 16-bit value, but we only currently allow the low order bits to be set
|
|
||||||
avr.OCR1AL.Set(value8) // set pwm duty
|
|
||||||
case 10:
|
|
||||||
// connect pwm to pin on timer 1, channel B
|
|
||||||
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1)
|
|
||||||
// this is a 16-bit value, but we only currently allow the low order bits to be set
|
|
||||||
avr.OCR1BL.Set(value8) // set pwm duty
|
|
||||||
case 11:
|
|
||||||
// connect pwm to pin on timer 2, channel A
|
|
||||||
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
|
|
||||||
avr.OCR2A.Set(value8) // set pwm duty
|
|
||||||
default:
|
|
||||||
panic("Invalid PWM pin")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// I2CConfig is used to store config info for I2C.
|
// I2CConfig is used to store config info for I2C.
|
||||||
type I2CConfig struct {
|
type I2CConfig struct {
|
||||||
Frequency uint32
|
Frequency uint32
|
||||||
|
|||||||
@@ -14,12 +14,58 @@ func CPUFrequency() uint32 {
|
|||||||
return 20000000
|
return 20000000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
portA Pin = iota * 8
|
||||||
|
portB
|
||||||
|
portC
|
||||||
|
portD
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PA0 = portA + 0
|
||||||
|
PA1 = portA + 1
|
||||||
|
PA2 = portA + 2
|
||||||
|
PA3 = portA + 3
|
||||||
|
PA4 = portA + 4
|
||||||
|
PA5 = portA + 5
|
||||||
|
PA6 = portA + 6
|
||||||
|
PA7 = portA + 7
|
||||||
|
PB0 = portB + 0
|
||||||
|
PB1 = portB + 1
|
||||||
|
PB2 = portB + 2
|
||||||
|
PB3 = portB + 3
|
||||||
|
PB4 = portB + 4
|
||||||
|
PB5 = portB + 5
|
||||||
|
PB6 = portB + 6
|
||||||
|
PB7 = portB + 7
|
||||||
|
PC0 = portC + 0
|
||||||
|
PC1 = portC + 1
|
||||||
|
PC2 = portC + 2
|
||||||
|
PC3 = portC + 3
|
||||||
|
PC4 = portC + 4
|
||||||
|
PC5 = portC + 5
|
||||||
|
PC6 = portC + 6
|
||||||
|
PC7 = portC + 7
|
||||||
|
PD0 = portD + 0
|
||||||
|
PD1 = portD + 1
|
||||||
|
PD2 = portD + 2
|
||||||
|
PD3 = portD + 3
|
||||||
|
PD4 = portD + 4
|
||||||
|
PD5 = portD + 5
|
||||||
|
PD6 = portD + 6
|
||||||
|
PD7 = portD + 7
|
||||||
|
)
|
||||||
|
|
||||||
|
// getPortMask returns the PORTx register and mask for the pin.
|
||||||
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
||||||
if p < 8 {
|
switch {
|
||||||
return avr.PORTD, 1 << uint8(p)
|
case p >= PA0 && p <= PA7:
|
||||||
} else if p < 14 {
|
return avr.PORTA, 1 << uint8(p-portA)
|
||||||
return avr.PORTB, 1 << uint8(p-8)
|
case p >= PB0 && p <= PB7:
|
||||||
} else {
|
return avr.PORTB, 1 << uint8(p-portB)
|
||||||
return avr.PORTC, 1 << uint8(p-14)
|
case p >= PC0 && p <= PC7:
|
||||||
|
return avr.PORTC, 1 << uint8(p-portC)
|
||||||
|
default:
|
||||||
|
return avr.PORTD, 1 << uint8(p-portD)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,53 +96,32 @@ const (
|
|||||||
PL7 = portE + 7
|
PL7 = portE + 7
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configure sets the pin to input or output.
|
// getPortMask returns the PORTx register and mask for the pin.
|
||||||
func (p Pin) Configure(config PinConfig) {
|
|
||||||
register, _, mask := p.getRegisterPortMask()
|
|
||||||
if config.Mode == PinOutput { // set output bit
|
|
||||||
register.SetBits(mask)
|
|
||||||
} else { // configure input: clear output bit
|
|
||||||
register.ClearBits(mask)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the current value of a GPIO pin.
|
|
||||||
func (p Pin) Get() bool {
|
|
||||||
_, port, mask := p.getRegisterPortMask()
|
|
||||||
return (port.Get() & mask) > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
||||||
_, port, mask := p.getRegisterPortMask()
|
|
||||||
return port, mask
|
|
||||||
}
|
|
||||||
|
|
||||||
// getRegisterPortMask returns the register, port, and mask for the pin
|
|
||||||
func (p Pin) getRegisterPortMask() (*volatile.Register8, *volatile.Register8, uint8) {
|
|
||||||
switch {
|
switch {
|
||||||
case p >= PA0 && p <= PA7:
|
case p >= PA0 && p <= PA7:
|
||||||
return avr.DDRA, avr.PORTA, 1 << uint8(p-portA)
|
return avr.PORTA, 1 << uint8(p-portA)
|
||||||
case p >= PB0 && p <= PB7:
|
case p >= PB0 && p <= PB7:
|
||||||
return avr.DDRB, avr.PORTB, 1 << uint8(p-portB)
|
return avr.PORTB, 1 << uint8(p-portB)
|
||||||
case p >= PC0 && p <= PC7:
|
case p >= PC0 && p <= PC7:
|
||||||
return avr.DDRC, avr.PORTC, 1 << uint8(p-portC)
|
return avr.PORTC, 1 << uint8(p-portC)
|
||||||
case p >= PD0 && p <= PD7:
|
case p >= PD0 && p <= PD7:
|
||||||
return avr.DDRD, avr.PORTD, 1 << uint8(p-portD)
|
return avr.PORTD, 1 << uint8(p-portD)
|
||||||
case p >= PE0 && p <= PE6:
|
case p >= PE0 && p <= PE6:
|
||||||
return avr.DDRE, avr.PORTE, 1 << uint8(p-portE)
|
return avr.PORTE, 1 << uint8(p-portE)
|
||||||
case p >= PF0 && p <= PF7:
|
case p >= PF0 && p <= PF7:
|
||||||
return avr.DDRF, avr.PORTF, 1 << uint8(p-portF)
|
return avr.PORTF, 1 << uint8(p-portF)
|
||||||
case p >= PG0 && p <= PG5:
|
case p >= PG0 && p <= PG5:
|
||||||
return avr.DDRG, avr.PORTG, 1 << uint8(p-portG)
|
return avr.PORTG, 1 << uint8(p-portG)
|
||||||
case p >= PH0 && p <= PH6:
|
case p >= PH0 && p <= PH6:
|
||||||
return avr.DDRH, avr.PORTH, 1 << uint8(p-portH)
|
return avr.PORTH, 1 << uint8(p-portH)
|
||||||
case p >= PJ0 && p <= PJ1:
|
case p >= PJ0 && p <= PJ1:
|
||||||
return avr.DDRJ, avr.PORTJ, 1 << uint8(p-portJ)
|
return avr.PORTJ, 1 << uint8(p-portJ)
|
||||||
case p >= PK0 && p <= PK7:
|
case p >= PK0 && p <= PK7:
|
||||||
return avr.DDRK, avr.PORTK, 1 << uint8(p-portK)
|
return avr.PORTK, 1 << uint8(p-portK)
|
||||||
case p >= PL0 && p <= PL7:
|
case p >= PL0 && p <= PL7:
|
||||||
return avr.DDRL, avr.PORTL, 1 << uint8(p-portL)
|
return avr.PORTL, 1 << uint8(p-portL)
|
||||||
default:
|
default:
|
||||||
return avr.DDRB, avr.PORTA, 255
|
return avr.PORTA, 255
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,47 +9,82 @@ import (
|
|||||||
|
|
||||||
const irq_USART0_RX = avr.IRQ_USART_RX
|
const irq_USART0_RX = avr.IRQ_USART_RX
|
||||||
|
|
||||||
// Configure sets the pin to input or output.
|
// getPortMask returns the PORTx register and mask for the pin.
|
||||||
func (p Pin) Configure(config PinConfig) {
|
|
||||||
if config.Mode == PinOutput { // set output bit
|
|
||||||
if p < 8 {
|
|
||||||
avr.DDRD.SetBits(1 << uint8(p))
|
|
||||||
} else if p < 14 {
|
|
||||||
avr.DDRB.SetBits(1 << uint8(p-8))
|
|
||||||
} else {
|
|
||||||
avr.DDRC.SetBits(1 << uint8(p-14))
|
|
||||||
}
|
|
||||||
} else { // configure input: clear output bit
|
|
||||||
if p < 8 {
|
|
||||||
avr.DDRD.ClearBits(1 << uint8(p))
|
|
||||||
} else if p < 14 {
|
|
||||||
avr.DDRB.ClearBits(1 << uint8(p-8))
|
|
||||||
} else {
|
|
||||||
avr.DDRC.ClearBits(1 << uint8(p-14))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get returns the current value of a GPIO pin.
|
|
||||||
func (p Pin) Get() bool {
|
|
||||||
if p < 8 {
|
|
||||||
val := avr.PIND.Get() & (1 << uint8(p))
|
|
||||||
return (val > 0)
|
|
||||||
} else if p < 14 {
|
|
||||||
val := avr.PINB.Get() & (1 << uint8(p-8))
|
|
||||||
return (val > 0)
|
|
||||||
} else {
|
|
||||||
val := avr.PINC.Get() & (1 << uint8(p-14))
|
|
||||||
return (val > 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
||||||
if p < 8 {
|
switch {
|
||||||
return avr.PORTD, 1 << uint8(p)
|
case p >= PB0 && p <= PB7: // port B
|
||||||
} else if p < 14 {
|
return avr.PORTB, 1 << uint8(p-portB)
|
||||||
return avr.PORTB, 1 << uint8(p-8)
|
case p >= PC0 && p <= PC7: // port C
|
||||||
} else {
|
return avr.PORTC, 1 << uint8(p-portC)
|
||||||
return avr.PORTC, 1 << uint8(p-14)
|
default: // port D
|
||||||
|
return avr.PORTD, 1 << uint8(p-portD)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// InitPWM initializes the registers needed for PWM.
|
||||||
|
func InitPWM() {
|
||||||
|
// use waveform generation
|
||||||
|
avr.TCCR0A.SetBits(avr.TCCR0A_WGM00)
|
||||||
|
|
||||||
|
// set timer 0 prescale factor to 64
|
||||||
|
avr.TCCR0B.SetBits(avr.TCCR0B_CS01 | avr.TCCR0B_CS00)
|
||||||
|
|
||||||
|
// set timer 1 prescale factor to 64
|
||||||
|
avr.TCCR1B.SetBits(avr.TCCR1B_CS11)
|
||||||
|
|
||||||
|
// put timer 1 in 8-bit phase correct pwm mode
|
||||||
|
avr.TCCR1A.SetBits(avr.TCCR1A_WGM10)
|
||||||
|
|
||||||
|
// set timer 2 prescale factor to 64
|
||||||
|
avr.TCCR2B.SetBits(avr.TCCR2B_CS22)
|
||||||
|
|
||||||
|
// configure timer 2 for phase correct pwm (8-bit)
|
||||||
|
avr.TCCR2A.SetBits(avr.TCCR2A_WGM20)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure configures a PWM pin for output.
|
||||||
|
func (pwm PWM) Configure() error {
|
||||||
|
switch pwm.Pin / 8 {
|
||||||
|
case 0: // port B
|
||||||
|
avr.DDRB.SetBits(1 << uint8(pwm.Pin))
|
||||||
|
case 2: // port D
|
||||||
|
avr.DDRD.SetBits(1 << uint8(pwm.Pin-16))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set turns on the duty cycle for a PWM pin using the provided value. On the AVR this is normally a
|
||||||
|
// 8-bit value ranging from 0 to 255.
|
||||||
|
func (pwm PWM) Set(value uint16) {
|
||||||
|
value8 := uint8(value >> 8)
|
||||||
|
switch pwm.Pin {
|
||||||
|
case PD3:
|
||||||
|
// connect pwm to pin on timer 2, channel B
|
||||||
|
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1)
|
||||||
|
avr.OCR2B.Set(value8) // set pwm duty
|
||||||
|
case PD5:
|
||||||
|
// connect pwm to pin on timer 0, channel B
|
||||||
|
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
|
||||||
|
avr.OCR0B.Set(value8) // set pwm duty
|
||||||
|
case PD6:
|
||||||
|
// connect pwm to pin on timer 0, channel A
|
||||||
|
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1)
|
||||||
|
avr.OCR0A.Set(value8) // set pwm duty
|
||||||
|
case PB1:
|
||||||
|
// connect pwm to pin on timer 1, channel A
|
||||||
|
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1)
|
||||||
|
// this is a 16-bit value, but we only currently allow the low order bits to be set
|
||||||
|
avr.OCR1AL.Set(value8) // set pwm duty
|
||||||
|
case PB2:
|
||||||
|
// connect pwm to pin on timer 1, channel B
|
||||||
|
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1)
|
||||||
|
// this is a 16-bit value, but we only currently allow the low order bits to be set
|
||||||
|
avr.OCR1BL.Set(value8) // set pwm duty
|
||||||
|
case PB3:
|
||||||
|
// connect pwm to pin on timer 2, channel A
|
||||||
|
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
|
||||||
|
avr.OCR2A.Set(value8) // set pwm duty
|
||||||
|
default:
|
||||||
|
panic("Invalid PWM pin")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+175
-19
@@ -33,6 +33,26 @@ const (
|
|||||||
PinInputPulldown PinMode = 12
|
PinInputPulldown PinMode = 12
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PinChange uint8
|
||||||
|
|
||||||
|
// Pin change interrupt constants for SetInterrupt.
|
||||||
|
const (
|
||||||
|
PinRising PinChange = sam.EIC_CONFIG_SENSE0_RISE
|
||||||
|
PinFalling PinChange = sam.EIC_CONFIG_SENSE0_FALL
|
||||||
|
PinToggle PinChange = sam.EIC_CONFIG_SENSE0_BOTH
|
||||||
|
)
|
||||||
|
|
||||||
|
// Callbacks to be called for pins configured with SetInterrupt. Unfortunately,
|
||||||
|
// we also need to keep track of which interrupt channel is used by which pin,
|
||||||
|
// as the only alternative would be iterating through all pins.
|
||||||
|
//
|
||||||
|
// We're using the magic constant 16 here because the SAM D21 has 16 interrupt
|
||||||
|
// channels configurable for pins.
|
||||||
|
var (
|
||||||
|
interruptPins [16]Pin // warning: the value is invalid when pinCallbacks[i] is not set!
|
||||||
|
pinCallbacks [16]func(Pin)
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
pinPadMapSERCOM0Pad0 byte = (0x10 << 1) | 0x00
|
pinPadMapSERCOM0Pad0 byte = (0x10 << 1) | 0x00
|
||||||
pinPadMapSERCOM1Pad0 byte = (0x20 << 1) | 0x00
|
pinPadMapSERCOM1Pad0 byte = (0x20 << 1) | 0x00
|
||||||
@@ -144,6 +164,114 @@ func findPinPadMapping(sercom uint8, pin Pin) (pinMode PinMode, pad uint32, ok b
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetInterrupt sets an interrupt to be executed when a particular pin changes
|
||||||
|
// state.
|
||||||
|
//
|
||||||
|
// This call will replace a previously set callback on this pin. You can pass a
|
||||||
|
// nil func to unset the pin change interrupt. If you do so, the change
|
||||||
|
// parameter is ignored and can be set to any value (such as 0).
|
||||||
|
func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
|
||||||
|
// Most pins follow a common pattern where the EXTINT value is the pin
|
||||||
|
// number modulo 16. However, there are a few exceptions, as you can see
|
||||||
|
// below.
|
||||||
|
extint := uint8(0)
|
||||||
|
switch p {
|
||||||
|
case PA08:
|
||||||
|
// Connected to NMI. This is not currently supported.
|
||||||
|
return ErrInvalidInputPin
|
||||||
|
case PA24:
|
||||||
|
extint = 12
|
||||||
|
case PA25:
|
||||||
|
extint = 13
|
||||||
|
case PA27:
|
||||||
|
extint = 15
|
||||||
|
case PA28:
|
||||||
|
extint = 8
|
||||||
|
case PA30:
|
||||||
|
extint = 10
|
||||||
|
case PA31:
|
||||||
|
extint = 11
|
||||||
|
default:
|
||||||
|
// All other pins follow a normal pattern.
|
||||||
|
extint = uint8(p) % 16
|
||||||
|
}
|
||||||
|
|
||||||
|
if callback == nil {
|
||||||
|
// Disable this pin interrupt (if it was enabled).
|
||||||
|
sam.EIC.INTENCLR.Set(1 << extint)
|
||||||
|
if pinCallbacks[extint] != nil {
|
||||||
|
pinCallbacks[extint] = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if pinCallbacks[extint] != nil {
|
||||||
|
// The pin was already configured.
|
||||||
|
// To properly re-configure a pin, unset it first and set a new
|
||||||
|
// configuration.
|
||||||
|
return ErrNoPinChangeChannel
|
||||||
|
}
|
||||||
|
pinCallbacks[extint] = callback
|
||||||
|
interruptPins[extint] = p
|
||||||
|
|
||||||
|
if sam.EIC.CTRL.Get() == 0 {
|
||||||
|
// EIC peripheral has not yet been initialized. Initialize it now.
|
||||||
|
|
||||||
|
// The EIC needs two clocks: CLK_EIC_APB and GCLK_EIC. CLK_EIC_APB is
|
||||||
|
// enabled by default, so doesn't have to be re-enabled. The other is
|
||||||
|
// required for detecting edges and must be enabled manually.
|
||||||
|
sam.GCLK.CLKCTRL.Set(sam.GCLK_CLKCTRL_ID_EIC<<sam.GCLK_CLKCTRL_ID_Pos |
|
||||||
|
sam.GCLK_CLKCTRL_GEN_GCLK0<<sam.GCLK_CLKCTRL_GEN_Pos |
|
||||||
|
sam.GCLK_CLKCTRL_CLKEN)
|
||||||
|
|
||||||
|
// should not be necessary (CLKCTRL is not synchronized)
|
||||||
|
for sam.GCLK.STATUS.HasBits(sam.GCLK_STATUS_SYNCBUSY) {
|
||||||
|
}
|
||||||
|
|
||||||
|
sam.EIC.CTRL.Set(sam.EIC_CTRL_ENABLE)
|
||||||
|
for sam.EIC.STATUS.HasBits(sam.EIC_STATUS_SYNCBUSY) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure this pin. Set the 4 bits of the EIC.CONFIGx register to the
|
||||||
|
// sense value (filter bit set to 0, sense bits set to the change value).
|
||||||
|
addr := &sam.EIC.CONFIG0
|
||||||
|
if extint >= 8 {
|
||||||
|
addr = &sam.EIC.CONFIG1
|
||||||
|
}
|
||||||
|
pos := (extint % 8) * 4 // bit position in register
|
||||||
|
addr.Set((addr.Get() &^ (0xf << pos)) | uint32(change)<<pos)
|
||||||
|
|
||||||
|
// Enable external interrupt for this pin.
|
||||||
|
sam.EIC.INTENSET.Set(1 << extint)
|
||||||
|
|
||||||
|
// Set the PMUXEN flag, while keeping the INEN and PULLEN flags (if they
|
||||||
|
// were set before). This avoids clearing the pin pull mode while
|
||||||
|
// configuring the pin interrupt.
|
||||||
|
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | (p.getPinCfg() & (sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)))
|
||||||
|
if p&1 > 0 {
|
||||||
|
// odd pin, so save the even pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
|
||||||
|
p.setPMux(val | (sam.PORT_PMUX0_PMUXO_A << sam.PORT_PMUX0_PMUXO_Pos))
|
||||||
|
} else {
|
||||||
|
// even pin, so save the odd pins
|
||||||
|
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
||||||
|
p.setPMux(val | (sam.PORT_PMUX0_PMUXE_A << sam.PORT_PMUX0_PMUXE_Pos))
|
||||||
|
}
|
||||||
|
|
||||||
|
interrupt.New(sam.IRQ_EIC, func(interrupt.Interrupt) {
|
||||||
|
flags := sam.EIC.INTFLAG.Get()
|
||||||
|
sam.EIC.INTFLAG.Set(flags) // clear interrupt
|
||||||
|
for i := uint(0); i < 16; i++ { // there are 16 channels
|
||||||
|
if flags&(1<<i) != 0 {
|
||||||
|
pinCallbacks[i](interruptPins[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).Enable()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// InitADC initializes the ADC.
|
// InitADC initializes the ADC.
|
||||||
func InitADC() {
|
func InitADC() {
|
||||||
// ADC Bias Calibration
|
// ADC Bias Calibration
|
||||||
@@ -260,6 +388,16 @@ func (a ADC) getADCChannel() uint8 {
|
|||||||
switch a.Pin {
|
switch a.Pin {
|
||||||
case PA02:
|
case PA02:
|
||||||
return 0
|
return 0
|
||||||
|
case PA03:
|
||||||
|
return 1
|
||||||
|
case PB04:
|
||||||
|
return 12
|
||||||
|
case PB05:
|
||||||
|
return 13
|
||||||
|
case PB06:
|
||||||
|
return 14
|
||||||
|
case PB07:
|
||||||
|
return 15
|
||||||
case PB08:
|
case PB08:
|
||||||
return 2
|
return 2
|
||||||
case PB09:
|
case PB09:
|
||||||
@@ -272,14 +410,22 @@ func (a ADC) getADCChannel() uint8 {
|
|||||||
return 6
|
return 6
|
||||||
case PA07:
|
case PA07:
|
||||||
return 7
|
return 7
|
||||||
|
case PA08:
|
||||||
|
return 16
|
||||||
|
case PA09:
|
||||||
|
return 17
|
||||||
|
case PA10:
|
||||||
|
return 18
|
||||||
|
case PA11:
|
||||||
|
return 19
|
||||||
|
case PB00:
|
||||||
|
return 8
|
||||||
|
case PB01:
|
||||||
|
return 9
|
||||||
case PB02:
|
case PB02:
|
||||||
return 10
|
return 10
|
||||||
case PB03:
|
case PB03:
|
||||||
return 11
|
return 11
|
||||||
case PA09:
|
|
||||||
return 17
|
|
||||||
case PA11:
|
|
||||||
return 19
|
|
||||||
default:
|
default:
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -1090,9 +1236,12 @@ func InitPWM() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure configures a PWM pin for output.
|
// Configure configures a PWM pin for output.
|
||||||
func (pwm PWM) Configure() {
|
func (pwm PWM) Configure() error {
|
||||||
// figure out which TCCX timer for this pin
|
// figure out which TCCX timer for this pin
|
||||||
timer := pwm.getTimer()
|
timer := pwm.getTimer()
|
||||||
|
if timer == nil {
|
||||||
|
return ErrInvalidOutputPin
|
||||||
|
}
|
||||||
|
|
||||||
// disable timer
|
// disable timer
|
||||||
timer.CTRLA.ClearBits(sam.TCC_CTRLA_ENABLE)
|
timer.CTRLA.ClearBits(sam.TCC_CTRLA_ENABLE)
|
||||||
@@ -1139,12 +1288,19 @@ func (pwm PWM) Configure() {
|
|||||||
val := pwm.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
val := pwm.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
|
||||||
pwm.setPMux(val | uint8(pwmConfig<<sam.PORT_PMUX0_PMUXE_Pos))
|
pwm.setPMux(val | uint8(pwmConfig<<sam.PORT_PMUX0_PMUXE_Pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set turns on the duty cycle for a PWM pin using the provided value.
|
// Set turns on the duty cycle for a PWM pin using the provided value.
|
||||||
func (pwm PWM) Set(value uint16) {
|
func (pwm PWM) Set(value uint16) {
|
||||||
// figure out which TCCX timer for this pin
|
// figure out which TCCX timer for this pin
|
||||||
timer := pwm.getTimer()
|
timer := pwm.getTimer()
|
||||||
|
if timer == nil {
|
||||||
|
// The Configure call above cannot have succeeded, so simply ignore this
|
||||||
|
// error.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// disable output
|
// disable output
|
||||||
timer.CTRLA.ClearBits(sam.TCC_CTRLA_ENABLE)
|
timer.CTRLA.ClearBits(sam.TCC_CTRLA_ENABLE)
|
||||||
@@ -1154,7 +1310,7 @@ func (pwm PWM) Set(value uint16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Set PWM signal to output duty cycle
|
// Set PWM signal to output duty cycle
|
||||||
pwm.setChannel(uint32(value))
|
pwm.setChannel(timer, uint32(value))
|
||||||
|
|
||||||
// Wait for synchronization on all channels
|
// Wait for synchronization on all channels
|
||||||
for timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CC0 |
|
for timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CC0 |
|
||||||
@@ -1223,32 +1379,32 @@ func (pwm PWM) getTimer() *sam.TCC_Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// setChannel sets the value for the correct channel for PWM on this pin
|
// setChannel sets the value for the correct channel for PWM on this pin
|
||||||
func (pwm PWM) setChannel(val uint32) {
|
func (pwm PWM) setChannel(timer *sam.TCC_Type, val uint32) {
|
||||||
switch pwm.Pin {
|
switch pwm.Pin {
|
||||||
case 6:
|
case 6:
|
||||||
pwm.getTimer().CC0.Set(val)
|
timer.CC0.Set(val)
|
||||||
case 7:
|
case 7:
|
||||||
pwm.getTimer().CC1.Set(val)
|
timer.CC1.Set(val)
|
||||||
case 8:
|
case 8:
|
||||||
pwm.getTimer().CC0.Set(val)
|
timer.CC0.Set(val)
|
||||||
case 9:
|
case 9:
|
||||||
pwm.getTimer().CC1.Set(val)
|
timer.CC1.Set(val)
|
||||||
case 14:
|
case 14:
|
||||||
pwm.getTimer().CC0.Set(val)
|
timer.CC0.Set(val)
|
||||||
case 15:
|
case 15:
|
||||||
pwm.getTimer().CC1.Set(val)
|
timer.CC1.Set(val)
|
||||||
case 16:
|
case 16:
|
||||||
pwm.getTimer().CC2.Set(val)
|
timer.CC2.Set(val)
|
||||||
case 17:
|
case 17:
|
||||||
pwm.getTimer().CC3.Set(val)
|
timer.CC3.Set(val)
|
||||||
case 18:
|
case 18:
|
||||||
pwm.getTimer().CC2.Set(val)
|
timer.CC2.Set(val)
|
||||||
case 19:
|
case 19:
|
||||||
pwm.getTimer().CC3.Set(val)
|
timer.CC3.Set(val)
|
||||||
case 20:
|
case 20:
|
||||||
pwm.getTimer().CC2.Set(val)
|
timer.CC2.Set(val)
|
||||||
case 21:
|
case 21:
|
||||||
pwm.getTimer().CC3.Set(val)
|
timer.CC3.Set(val)
|
||||||
default:
|
default:
|
||||||
return // not supported on this pin
|
return // not supported on this pin
|
||||||
}
|
}
|
||||||
|
|||||||
+310
-62
@@ -44,6 +44,26 @@ const (
|
|||||||
PinInputPulldown PinMode = 18
|
PinInputPulldown PinMode = 18
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PinChange uint8
|
||||||
|
|
||||||
|
// Pin change interrupt constants for SetInterrupt.
|
||||||
|
const (
|
||||||
|
PinRising PinChange = sam.EIC_CONFIG_SENSE0_RISE
|
||||||
|
PinFalling PinChange = sam.EIC_CONFIG_SENSE0_FALL
|
||||||
|
PinToggle PinChange = sam.EIC_CONFIG_SENSE0_BOTH
|
||||||
|
)
|
||||||
|
|
||||||
|
// Callbacks to be called for pins configured with SetInterrupt. Unfortunately,
|
||||||
|
// we also need to keep track of which interrupt channel is used by which pin,
|
||||||
|
// as the only alternative would be iterating through all pins.
|
||||||
|
//
|
||||||
|
// We're using the magic constant 16 here because the SAM D21 has 16 interrupt
|
||||||
|
// channels configurable for pins.
|
||||||
|
var (
|
||||||
|
interruptPins [16]Pin // warning: the value is invalid when pinCallbacks[i] is not set!
|
||||||
|
pinCallbacks [16]func(Pin)
|
||||||
|
)
|
||||||
|
|
||||||
// Hardware pins
|
// Hardware pins
|
||||||
const (
|
const (
|
||||||
PA00 Pin = 0
|
PA00 Pin = 0
|
||||||
@@ -110,6 +130,70 @@ const (
|
|||||||
PB29 Pin = 61
|
PB29 Pin = 61
|
||||||
PB30 Pin = 62
|
PB30 Pin = 62
|
||||||
PB31 Pin = 63
|
PB31 Pin = 63
|
||||||
|
PC00 Pin = 64
|
||||||
|
PC01 Pin = 65
|
||||||
|
PC02 Pin = 66
|
||||||
|
PC03 Pin = 67
|
||||||
|
PC04 Pin = 68
|
||||||
|
PC05 Pin = 69
|
||||||
|
PC06 Pin = 70
|
||||||
|
PC07 Pin = 71
|
||||||
|
PC08 Pin = 72
|
||||||
|
PC09 Pin = 73
|
||||||
|
PC10 Pin = 74
|
||||||
|
PC11 Pin = 75
|
||||||
|
PC12 Pin = 76
|
||||||
|
PC13 Pin = 77
|
||||||
|
PC14 Pin = 78
|
||||||
|
PC15 Pin = 79
|
||||||
|
PC16 Pin = 80
|
||||||
|
PC17 Pin = 81
|
||||||
|
PC18 Pin = 82
|
||||||
|
PC19 Pin = 83
|
||||||
|
PC20 Pin = 84
|
||||||
|
PC21 Pin = 85
|
||||||
|
PC22 Pin = 86
|
||||||
|
PC23 Pin = 87
|
||||||
|
PC24 Pin = 88
|
||||||
|
PC25 Pin = 89
|
||||||
|
PC26 Pin = 90
|
||||||
|
PC27 Pin = 91
|
||||||
|
PC28 Pin = 92
|
||||||
|
PC29 Pin = 93
|
||||||
|
PC30 Pin = 94
|
||||||
|
PC31 Pin = 95
|
||||||
|
PD00 Pin = 96
|
||||||
|
PD01 Pin = 97
|
||||||
|
PD02 Pin = 98
|
||||||
|
PD03 Pin = 99
|
||||||
|
PD04 Pin = 100
|
||||||
|
PD05 Pin = 101
|
||||||
|
PD06 Pin = 102
|
||||||
|
PD07 Pin = 103
|
||||||
|
PD08 Pin = 104
|
||||||
|
PD09 Pin = 105
|
||||||
|
PD10 Pin = 106
|
||||||
|
PD11 Pin = 107
|
||||||
|
PD12 Pin = 108
|
||||||
|
PD13 Pin = 109
|
||||||
|
PD14 Pin = 110
|
||||||
|
PD15 Pin = 111
|
||||||
|
PD16 Pin = 112
|
||||||
|
PD17 Pin = 113
|
||||||
|
PD18 Pin = 114
|
||||||
|
PD19 Pin = 115
|
||||||
|
PD20 Pin = 116
|
||||||
|
PD21 Pin = 117
|
||||||
|
PD22 Pin = 118
|
||||||
|
PD23 Pin = 119
|
||||||
|
PD24 Pin = 120
|
||||||
|
PD25 Pin = 121
|
||||||
|
PD26 Pin = 122
|
||||||
|
PD27 Pin = 123
|
||||||
|
PD28 Pin = 124
|
||||||
|
PD29 Pin = 125
|
||||||
|
PD30 Pin = 126
|
||||||
|
PD31 Pin = 127
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -180,7 +264,7 @@ const (
|
|||||||
// easy to check whether a nibble is set at all.
|
// easy to check whether a nibble is set at all.
|
||||||
//
|
//
|
||||||
// Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/60001507E.pdf
|
// Datasheet: http://ww1.microchip.com/downloads/en/DeviceDoc/60001507E.pdf
|
||||||
var pinPadMapping = [32]uint16{
|
var pinPadMapping = [64]uint16{
|
||||||
// page 32
|
// page 32
|
||||||
PA00 / 2: 0 | pinPadMapSERCOM1AltPad0,
|
PA00 / 2: 0 | pinPadMapSERCOM1AltPad0,
|
||||||
|
|
||||||
@@ -188,28 +272,28 @@ var pinPadMapping = [32]uint16{
|
|||||||
PB08 / 2: 0 | pinPadMapSERCOM4AltPad0,
|
PB08 / 2: 0 | pinPadMapSERCOM4AltPad0,
|
||||||
PA04 / 2: 0 | pinPadMapSERCOM0AltPad0,
|
PA04 / 2: 0 | pinPadMapSERCOM0AltPad0,
|
||||||
PA06 / 2: 0 | pinPadMapSERCOM0AltPad2,
|
PA06 / 2: 0 | pinPadMapSERCOM0AltPad2,
|
||||||
//PC04 / 2: pinPadMapSERCOM6Pad0 | 0,
|
PC04 / 2: pinPadMapSERCOM6Pad0 | 0,
|
||||||
//PC06 / 2: pinPadMapSERCOM6Pad2 | 0,
|
PC06 / 2: pinPadMapSERCOM6Pad2 | 0,
|
||||||
PA08 / 2: pinPadMapSERCOM0Pad0 | pinPadMapSERCOM2AltPad1,
|
PA08 / 2: pinPadMapSERCOM0Pad0 | pinPadMapSERCOM2AltPad1,
|
||||||
PA10 / 2: pinPadMapSERCOM0Pad2 | pinPadMapSERCOM2AltPad2,
|
PA10 / 2: pinPadMapSERCOM0Pad2 | pinPadMapSERCOM2AltPad2,
|
||||||
PB10 / 2: 0 | pinPadMapSERCOM4AltPad2,
|
PB10 / 2: 0 | pinPadMapSERCOM4AltPad2,
|
||||||
PB12 / 2: pinPadMapSERCOM4Pad0 | 0,
|
PB12 / 2: pinPadMapSERCOM4Pad0 | 0,
|
||||||
PB14 / 2: pinPadMapSERCOM4Pad2 | 0,
|
PB14 / 2: pinPadMapSERCOM4Pad2 | 0,
|
||||||
//PD08 / 2: pinPadMapSERCOM7Pad0 | pinPadMapSERCOM6AltPad1,
|
PD08 / 2: pinPadMapSERCOM7Pad0 | pinPadMapSERCOM6AltPad1,
|
||||||
//PD10 / 2: pinPadMapSERCOM7Pad2 | pinPadMapSERCOM6AltPad2,
|
PD10 / 2: pinPadMapSERCOM7Pad2 | pinPadMapSERCOM6AltPad2,
|
||||||
//PC10 / 2: pinPadMapSERCOM6Pad2 | pinPadMapSERCOM7AltPad2,
|
PC10 / 2: pinPadMapSERCOM6Pad2 | pinPadMapSERCOM7AltPad2,
|
||||||
|
|
||||||
// page 34
|
// page 34
|
||||||
//PC12 / 2: pinPadMapSERCOM7Pad0 | pinPadMapSERCOM6AltPad1,
|
PC12 / 2: pinPadMapSERCOM7Pad0 | pinPadMapSERCOM6AltPad1,
|
||||||
//PC14 / 2: pinPadMapSERCOM7Pad2 | pinPadMapSERCOM6AltPad2,
|
PC14 / 2: pinPadMapSERCOM7Pad2 | pinPadMapSERCOM6AltPad2,
|
||||||
PA12 / 2: pinPadMapSERCOM2Pad0 | pinPadMapSERCOM4AltPad1,
|
PA12 / 2: pinPadMapSERCOM2Pad0 | pinPadMapSERCOM4AltPad1,
|
||||||
PA14 / 2: pinPadMapSERCOM2Pad2 | pinPadMapSERCOM4AltPad2,
|
PA14 / 2: pinPadMapSERCOM2Pad2 | pinPadMapSERCOM4AltPad2,
|
||||||
PA16 / 2: pinPadMapSERCOM1Pad0 | pinPadMapSERCOM3AltPad1,
|
PA16 / 2: pinPadMapSERCOM1Pad0 | pinPadMapSERCOM3AltPad1,
|
||||||
PA18 / 2: pinPadMapSERCOM1Pad2 | pinPadMapSERCOM3AltPad2,
|
PA18 / 2: pinPadMapSERCOM1Pad2 | pinPadMapSERCOM3AltPad2,
|
||||||
//PC16 / 2: pinPadMapSERCOM6Pad0 | pinPadMapSERCOM0AltPad1,
|
PC16 / 2: pinPadMapSERCOM6Pad0 | pinPadMapSERCOM0AltPad1,
|
||||||
//PC18 / 2: pinPadMapSERCOM6Pad2 | pinPadMapSERCOM0AltPad2,
|
PC18 / 2: pinPadMapSERCOM6Pad2 | pinPadMapSERCOM0AltPad2,
|
||||||
//PC22 / 2: pinPadMapSERCOM1Pad0 | pinPadMapSERCOM3AltPad1,
|
PC22 / 2: pinPadMapSERCOM1Pad0 | pinPadMapSERCOM3AltPad1,
|
||||||
//PD20 / 2: pinPadMapSERCOM1Pad2 | pinPadMapSERCOM3AltPad2,
|
PD20 / 2: pinPadMapSERCOM1Pad2 | pinPadMapSERCOM3AltPad2,
|
||||||
PB16 / 2: pinPadMapSERCOM5Pad0 | 0,
|
PB16 / 2: pinPadMapSERCOM5Pad0 | 0,
|
||||||
PB18 / 2: pinPadMapSERCOM5Pad2 | pinPadMapSERCOM7AltPad2,
|
PB18 / 2: pinPadMapSERCOM5Pad2 | pinPadMapSERCOM7AltPad2,
|
||||||
|
|
||||||
@@ -222,7 +306,7 @@ var pinPadMapping = [32]uint16{
|
|||||||
PB24 / 2: pinPadMapSERCOM0Pad0 | pinPadMapSERCOM2AltPad1,
|
PB24 / 2: pinPadMapSERCOM0Pad0 | pinPadMapSERCOM2AltPad1,
|
||||||
PB26 / 2: pinPadMapSERCOM2Pad0 | pinPadMapSERCOM4AltPad1,
|
PB26 / 2: pinPadMapSERCOM2Pad0 | pinPadMapSERCOM4AltPad1,
|
||||||
PB28 / 2: pinPadMapSERCOM2Pad2 | pinPadMapSERCOM4AltPad2,
|
PB28 / 2: pinPadMapSERCOM2Pad2 | pinPadMapSERCOM4AltPad2,
|
||||||
//PC24 / 2: pinPadMapSERCOM0Pad2 | pinPadMapSERCOM2AltPad2,
|
PC24 / 2: pinPadMapSERCOM0Pad2 | pinPadMapSERCOM2AltPad2,
|
||||||
//PC26 / 2: pinPadMapSERCOM1Pad1 | 0, // note: PC26 doesn't support SERCOM, but PC27 does
|
//PC26 / 2: pinPadMapSERCOM1Pad1 | 0, // note: PC26 doesn't support SERCOM, but PC27 does
|
||||||
//PC28 / 2: pinPadMapSERCOM1Pad1 | 0, // note: PC29 doesn't exist in the datasheet?
|
//PC28 / 2: pinPadMapSERCOM1Pad1 | 0, // note: PC29 doesn't exist in the datasheet?
|
||||||
PA30 / 2: 0 | pinPadMapSERCOM1AltPad2,
|
PA30 / 2: 0 | pinPadMapSERCOM1AltPad2,
|
||||||
@@ -268,6 +352,162 @@ func findPinPadMapping(sercom uint8, pin Pin) (pinMode PinMode, pad uint32, ok b
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetInterrupt sets an interrupt to be executed when a particular pin changes
|
||||||
|
// state.
|
||||||
|
//
|
||||||
|
// This call will replace a previously set callback on this pin. You can pass a
|
||||||
|
// nil func to unset the pin change interrupt. If you do so, the change
|
||||||
|
// parameter is ignored and can be set to any value (such as 0).
|
||||||
|
func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
|
||||||
|
// Most pins follow a common pattern where the EXTINT value is the pin
|
||||||
|
// number modulo 16. However, there are a few exceptions, as you can see
|
||||||
|
// below.
|
||||||
|
extint := uint8(0)
|
||||||
|
|
||||||
|
switch p {
|
||||||
|
case PA08:
|
||||||
|
// Connected to NMI. This is not currently supported.
|
||||||
|
return ErrInvalidInputPin
|
||||||
|
case PB26:
|
||||||
|
extint = 12
|
||||||
|
case PB27:
|
||||||
|
extint = 13
|
||||||
|
case PB28:
|
||||||
|
extint = 14
|
||||||
|
case PB29:
|
||||||
|
extint = 15
|
||||||
|
case PC07:
|
||||||
|
extint = 9
|
||||||
|
case PD08:
|
||||||
|
extint = 3
|
||||||
|
case PD09:
|
||||||
|
extint = 4
|
||||||
|
case PD10:
|
||||||
|
extint = 5
|
||||||
|
case PD11:
|
||||||
|
extint = 6
|
||||||
|
case PD12:
|
||||||
|
extint = 7
|
||||||
|
case PD20:
|
||||||
|
extint = 10
|
||||||
|
case PD21:
|
||||||
|
extint = 11
|
||||||
|
default:
|
||||||
|
// All other pins follow a normal pattern.
|
||||||
|
extint = uint8(p) % 16
|
||||||
|
}
|
||||||
|
|
||||||
|
if callback == nil {
|
||||||
|
// Disable this pin interrupt (if it was enabled).
|
||||||
|
sam.EIC.INTENCLR.Set(1 << extint)
|
||||||
|
if pinCallbacks[extint] != nil {
|
||||||
|
pinCallbacks[extint] = nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if pinCallbacks[extint] != nil {
|
||||||
|
// The pin was already configured.
|
||||||
|
// To properly re-configure a pin, unset it first and set a new
|
||||||
|
// configuration.
|
||||||
|
return ErrNoPinChangeChannel
|
||||||
|
}
|
||||||
|
pinCallbacks[extint] = callback
|
||||||
|
interruptPins[extint] = p
|
||||||
|
|
||||||
|
if !sam.EIC.CTRLA.HasBits(sam.EIC_CTRLA_ENABLE) {
|
||||||
|
// EIC peripheral has not yet been initialized. Initialize it now.
|
||||||
|
|
||||||
|
// The EIC needs two clocks: CLK_EIC_APB and GCLK_EIC. CLK_EIC_APB is
|
||||||
|
// enabled by default, so doesn't have to be re-enabled. The other is
|
||||||
|
// required for detecting edges and must be enabled manually.
|
||||||
|
sam.GCLK.PCHCTRL[4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
|
||||||
|
|
||||||
|
// should not be necessary (CLKCTRL is not synchronized)
|
||||||
|
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK0 << sam.GCLK_SYNCBUSY_GENCTRL_Pos) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CONFIG register is enable-protected, so disable EIC.
|
||||||
|
sam.EIC.CTRLA.ClearBits(sam.EIC_CTRLA_ENABLE)
|
||||||
|
|
||||||
|
// Configure this pin. Set the 4 bits of the EIC.CONFIGx register to the
|
||||||
|
// sense value (filter bit set to 0, sense bits set to the change value).
|
||||||
|
addr := &sam.EIC.CONFIG[0]
|
||||||
|
if extint >= 8 {
|
||||||
|
addr = &sam.EIC.CONFIG[1]
|
||||||
|
}
|
||||||
|
pos := (extint % 8) * 4 // bit position in register
|
||||||
|
addr.Set((addr.Get() &^ (0xf << pos)) | uint32(change)<<pos)
|
||||||
|
|
||||||
|
// Enable external interrupt for this pin.
|
||||||
|
sam.EIC.INTENSET.Set(1 << extint)
|
||||||
|
|
||||||
|
sam.EIC.CTRLA.Set(sam.EIC_CTRLA_ENABLE)
|
||||||
|
for sam.EIC.SYNCBUSY.HasBits(sam.EIC_SYNCBUSY_ENABLE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the PMUXEN flag, while keeping the INEN and PULLEN flags (if they
|
||||||
|
// were set before). This avoids clearing the pin pull mode while
|
||||||
|
// configuring the pin interrupt.
|
||||||
|
p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN | (p.getPinCfg() & (sam.PORT_GROUP_PINCFG_INEN | sam.PORT_GROUP_PINCFG_PULLEN)))
|
||||||
|
if p&1 > 0 {
|
||||||
|
// odd pin, so save the even pins
|
||||||
|
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk
|
||||||
|
p.setPMux(val | (0 << sam.PORT_GROUP_PMUX_PMUXO_Pos))
|
||||||
|
} else {
|
||||||
|
// even pin, so save the odd pins
|
||||||
|
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXO_Msk
|
||||||
|
p.setPMux(val | (0 << sam.PORT_GROUP_PMUX_PMUXE_Pos))
|
||||||
|
}
|
||||||
|
|
||||||
|
handleEICInterrupt := func(interrupt.Interrupt) {
|
||||||
|
flags := sam.EIC.INTFLAG.Get()
|
||||||
|
sam.EIC.INTFLAG.Set(flags) // clear interrupt
|
||||||
|
for i := uint(0); i < 16; i++ { // there are 16 channels
|
||||||
|
if flags&(1<<i) != 0 {
|
||||||
|
pinCallbacks[i](interruptPins[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch extint {
|
||||||
|
case 0:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_0, handleEICInterrupt).Enable()
|
||||||
|
case 1:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_1, handleEICInterrupt).Enable()
|
||||||
|
case 2:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_2, handleEICInterrupt).Enable()
|
||||||
|
case 3:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_3, handleEICInterrupt).Enable()
|
||||||
|
case 4:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_4, handleEICInterrupt).Enable()
|
||||||
|
case 5:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_5, handleEICInterrupt).Enable()
|
||||||
|
case 6:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_6, handleEICInterrupt).Enable()
|
||||||
|
case 7:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_7, handleEICInterrupt).Enable()
|
||||||
|
case 8:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_8, handleEICInterrupt).Enable()
|
||||||
|
case 9:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_9, handleEICInterrupt).Enable()
|
||||||
|
case 10:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_10, handleEICInterrupt).Enable()
|
||||||
|
case 11:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_11, handleEICInterrupt).Enable()
|
||||||
|
case 12:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_12, handleEICInterrupt).Enable()
|
||||||
|
case 13:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_13, handleEICInterrupt).Enable()
|
||||||
|
case 14:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_14, handleEICInterrupt).Enable()
|
||||||
|
case 15:
|
||||||
|
interrupt.New(sam.IRQ_EIC_EXTINT_15, handleEICInterrupt).Enable()
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Return the register and mask to enable a given GPIO pin. This can be used to
|
// Return the register and mask to enable a given GPIO pin. This can be used to
|
||||||
// implement bit-banged drivers.
|
// implement bit-banged drivers.
|
||||||
func (p Pin) PortMaskSet() (*uint32, uint32) {
|
func (p Pin) PortMaskSet() (*uint32, uint32) {
|
||||||
@@ -586,7 +826,7 @@ func (a ADC) Get() uint16 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a ADC) getADCBus() *sam.ADC_Type {
|
func (a ADC) getADCBus() *sam.ADC_Type {
|
||||||
if a.Pin >= PB04 && a.Pin <= PB07 {
|
if (a.Pin >= PB04 && a.Pin <= PB07) || (a.Pin >= PC00) {
|
||||||
return sam.ADC1
|
return sam.ADC1
|
||||||
}
|
}
|
||||||
return sam.ADC0
|
return sam.ADC0
|
||||||
@@ -629,6 +869,24 @@ func (a ADC) getADCChannel() uint8 {
|
|||||||
return 8
|
return 8
|
||||||
case PB07:
|
case PB07:
|
||||||
return 9
|
return 9
|
||||||
|
|
||||||
|
case PC00:
|
||||||
|
return 10
|
||||||
|
case PC01:
|
||||||
|
return 11
|
||||||
|
case PC02:
|
||||||
|
return 4
|
||||||
|
case PC03:
|
||||||
|
return 5
|
||||||
|
case PC30:
|
||||||
|
return 12
|
||||||
|
case PC31:
|
||||||
|
return 13
|
||||||
|
|
||||||
|
case PD00:
|
||||||
|
return 14
|
||||||
|
case PD01:
|
||||||
|
return 15
|
||||||
default:
|
default:
|
||||||
panic("Invalid ADC pin")
|
panic("Invalid ADC pin")
|
||||||
}
|
}
|
||||||
@@ -645,28 +903,8 @@ type UART struct {
|
|||||||
var (
|
var (
|
||||||
// UART0 is actually a USB CDC interface.
|
// UART0 is actually a USB CDC interface.
|
||||||
UART0 = USBCDC{Buffer: NewRingBuffer()}
|
UART0 = USBCDC{Buffer: NewRingBuffer()}
|
||||||
|
|
||||||
// The first hardware serial port on the SAMD51. Uses the SERCOM3 interface.
|
|
||||||
UART1 = UART{
|
|
||||||
Buffer: NewRingBuffer(),
|
|
||||||
Bus: sam.SERCOM3_USART_INT,
|
|
||||||
SERCOM: 3,
|
|
||||||
}
|
|
||||||
|
|
||||||
// The second hardware serial port on the SAMD51. Uses the SERCOM0 interface.
|
|
||||||
UART2 = UART{
|
|
||||||
Buffer: NewRingBuffer(),
|
|
||||||
Bus: sam.SERCOM0_USART_INT,
|
|
||||||
SERCOM: 0,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
// Register RXC interrupts.
|
|
||||||
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM3_2, UART1.handleInterrupt)
|
|
||||||
UART2.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, UART2.handleInterrupt)
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
sampleRate16X = 16
|
sampleRate16X = 16
|
||||||
lsbFirst = 1
|
lsbFirst = 1
|
||||||
@@ -1216,7 +1454,7 @@ const (
|
|||||||
const period = 0xFFFF
|
const period = 0xFFFF
|
||||||
|
|
||||||
// Configure configures a PWM pin for output.
|
// Configure configures a PWM pin for output.
|
||||||
func (pwm PWM) Configure() {
|
func (pwm PWM) Configure() error {
|
||||||
// Set pin as output
|
// Set pin as output
|
||||||
sam.PORT.GROUP[0].DIRSET.Set(1 << uint8(pwm.Pin))
|
sam.PORT.GROUP[0].DIRSET.Set(1 << uint8(pwm.Pin))
|
||||||
// Set pin to low
|
// Set pin to low
|
||||||
@@ -1240,6 +1478,9 @@ func (pwm PWM) Configure() {
|
|||||||
|
|
||||||
// figure out which TCCX timer for this pin
|
// figure out which TCCX timer for this pin
|
||||||
timer := pwm.getTimer()
|
timer := pwm.getTimer()
|
||||||
|
if timer == nil {
|
||||||
|
return ErrInvalidOutputPin
|
||||||
|
}
|
||||||
|
|
||||||
// disable timer
|
// disable timer
|
||||||
timer.CTRLA.ClearBits(sam.TCC_CTRLA_ENABLE)
|
timer.CTRLA.ClearBits(sam.TCC_CTRLA_ENABLE)
|
||||||
@@ -1264,7 +1505,7 @@ func (pwm PWM) Configure() {
|
|||||||
|
|
||||||
// Set the initial value
|
// Set the initial value
|
||||||
// TCCx->CC[tcChannel].reg = (uint32_t) value;
|
// TCCx->CC[tcChannel].reg = (uint32_t) value;
|
||||||
pwm.setChannel(0)
|
pwm.setChannel(timer, 0)
|
||||||
|
|
||||||
for timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CC0) ||
|
for timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CC0) ||
|
||||||
timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CC1) {
|
timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CC1) {
|
||||||
@@ -1282,12 +1523,19 @@ func (pwm PWM) Configure() {
|
|||||||
// Wait for synchronization
|
// Wait for synchronization
|
||||||
for timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_ENABLE) {
|
for timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_ENABLE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set turns on the duty cycle for a PWM pin using the provided value.
|
// Set turns on the duty cycle for a PWM pin using the provided value.
|
||||||
func (pwm PWM) Set(value uint16) {
|
func (pwm PWM) Set(value uint16) {
|
||||||
// figure out which TCCX timer for this pin
|
// figure out which TCCX timer for this pin
|
||||||
timer := pwm.getTimer()
|
timer := pwm.getTimer()
|
||||||
|
if timer == nil {
|
||||||
|
// The Configure call above cannot have succeeded, so simply ignore this
|
||||||
|
// error.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Wait for synchronization
|
// Wait for synchronization
|
||||||
for timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CTRLB) {
|
for timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CTRLB) {
|
||||||
@@ -1297,7 +1545,7 @@ func (pwm PWM) Set(value uint16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TCCx->CCBUF[tcChannel].reg = (uint32_t) value;
|
// TCCx->CCBUF[tcChannel].reg = (uint32_t) value;
|
||||||
pwm.setChannelBuffer(uint32(value))
|
pwm.setChannelBuffer(timer, uint32(value))
|
||||||
|
|
||||||
for timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CC0) ||
|
for timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CC0) ||
|
||||||
timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CC1) {
|
timer.SYNCBUSY.HasBits(sam.TCC_SYNCBUSY_CC1) {
|
||||||
@@ -1329,61 +1577,61 @@ func (pwm PWM) setPinCfg(val uint8) {
|
|||||||
pwm.Pin.setPinCfg(val)
|
pwm.Pin.setPinCfg(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
// setChannel sets the value for the correct channel for PWM on this pin
|
// setChannel sets the value for the correct channel for PWM on this pin.
|
||||||
func (pwm PWM) setChannel(val uint32) {
|
func (pwm PWM) setChannel(timer *sam.TCC_Type, val uint32) {
|
||||||
switch pwm.Pin {
|
switch pwm.Pin {
|
||||||
case PA16:
|
case PA16:
|
||||||
pwm.getTimer().CC[0].Set(val)
|
timer.CC[0].Set(val)
|
||||||
case PA17:
|
case PA17:
|
||||||
pwm.getTimer().CC[1].Set(val)
|
timer.CC[1].Set(val)
|
||||||
case PA14:
|
case PA14:
|
||||||
pwm.getTimer().CC[0].Set(val)
|
timer.CC[0].Set(val)
|
||||||
case PA15:
|
case PA15:
|
||||||
pwm.getTimer().CC[1].Set(val)
|
timer.CC[1].Set(val)
|
||||||
case PA18:
|
case PA18:
|
||||||
pwm.getTimer().CC[2].Set(val)
|
timer.CC[2].Set(val)
|
||||||
case PA19:
|
case PA19:
|
||||||
pwm.getTimer().CC[3].Set(val)
|
timer.CC[3].Set(val)
|
||||||
case PA20:
|
case PA20:
|
||||||
pwm.getTimer().CC[0].Set(val)
|
timer.CC[0].Set(val)
|
||||||
case PA21:
|
case PA21:
|
||||||
pwm.getTimer().CC[1].Set(val)
|
timer.CC[1].Set(val)
|
||||||
case PA23:
|
case PA23:
|
||||||
pwm.getTimer().CC[3].Set(val)
|
timer.CC[3].Set(val)
|
||||||
case PA22:
|
case PA22:
|
||||||
pwm.getTimer().CC[2].Set(val)
|
timer.CC[2].Set(val)
|
||||||
case PB31:
|
case PB31:
|
||||||
pwm.getTimer().CC[1].Set(val)
|
timer.CC[1].Set(val)
|
||||||
default:
|
default:
|
||||||
return // not supported on this pin
|
return // not supported on this pin
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setChannelBuffer sets the value for the correct channel buffer for PWM on this pin
|
// setChannelBuffer sets the value for the correct channel buffer for PWM on this pin
|
||||||
func (pwm PWM) setChannelBuffer(val uint32) {
|
func (pwm PWM) setChannelBuffer(timer *sam.TCC_Type, val uint32) {
|
||||||
switch pwm.Pin {
|
switch pwm.Pin {
|
||||||
case PA16:
|
case PA16:
|
||||||
pwm.getTimer().CCBUF[0].Set(val)
|
timer.CCBUF[0].Set(val)
|
||||||
case PA17:
|
case PA17:
|
||||||
pwm.getTimer().CCBUF[1].Set(val)
|
timer.CCBUF[1].Set(val)
|
||||||
case PA14:
|
case PA14:
|
||||||
pwm.getTimer().CCBUF[0].Set(val)
|
timer.CCBUF[0].Set(val)
|
||||||
case PA15:
|
case PA15:
|
||||||
pwm.getTimer().CCBUF[1].Set(val)
|
timer.CCBUF[1].Set(val)
|
||||||
case PA18:
|
case PA18:
|
||||||
pwm.getTimer().CCBUF[2].Set(val)
|
timer.CCBUF[2].Set(val)
|
||||||
case PA19:
|
case PA19:
|
||||||
pwm.getTimer().CCBUF[3].Set(val)
|
timer.CCBUF[3].Set(val)
|
||||||
case PA20:
|
case PA20:
|
||||||
pwm.getTimer().CCBUF[0].Set(val)
|
timer.CCBUF[0].Set(val)
|
||||||
case PA21:
|
case PA21:
|
||||||
pwm.getTimer().CCBUF[1].Set(val)
|
timer.CCBUF[1].Set(val)
|
||||||
case PA23:
|
case PA23:
|
||||||
pwm.getTimer().CCBUF[3].Set(val)
|
timer.CCBUF[3].Set(val)
|
||||||
case PA22:
|
case PA22:
|
||||||
pwm.getTimer().CCBUF[2].Set(val)
|
timer.CCBUF[2].Set(val)
|
||||||
case PB31:
|
case PB31:
|
||||||
pwm.getTimer().CCBUF[1].Set(val)
|
timer.CCBUF[1].Set(val)
|
||||||
default:
|
default:
|
||||||
return // not supported on this pin
|
return // not supported on this pin
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// +build sam,atsamd51,atsamd51p19
|
||||||
|
|
||||||
|
// Peripheral abstraction layer for the atsamd51.
|
||||||
|
//
|
||||||
|
// Datasheet:
|
||||||
|
// http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf
|
||||||
|
//
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import "device/sam"
|
||||||
|
|
||||||
|
const HSRAM_SIZE = 0x00030000
|
||||||
|
|
||||||
|
// InitPWM initializes the PWM interface.
|
||||||
|
func InitPWM() {
|
||||||
|
// turn on timer clocks used for PWM
|
||||||
|
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_ | sam.MCLK_APBBMASK_TCC1_)
|
||||||
|
sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_)
|
||||||
|
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_TCC4_)
|
||||||
|
|
||||||
|
//use clock generator 0
|
||||||
|
sam.GCLK.PCHCTRL[25].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_PCHCTRL_CHEN)
|
||||||
|
sam.GCLK.PCHCTRL[29].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_PCHCTRL_CHEN)
|
||||||
|
sam.GCLK.PCHCTRL[38].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_PCHCTRL_CHEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
// getTimer returns the timer to be used for PWM on this pin
|
||||||
|
func (pwm PWM) getTimer() *sam.TCC_Type {
|
||||||
|
switch pwm.Pin {
|
||||||
|
case PA16:
|
||||||
|
return sam.TCC1
|
||||||
|
case PA17:
|
||||||
|
return sam.TCC1
|
||||||
|
case PA14:
|
||||||
|
return sam.TCC2
|
||||||
|
case PA15:
|
||||||
|
return sam.TCC2
|
||||||
|
case PA18:
|
||||||
|
return sam.TCC1
|
||||||
|
case PA19:
|
||||||
|
return sam.TCC1
|
||||||
|
case PA20:
|
||||||
|
return sam.TCC0
|
||||||
|
case PA21:
|
||||||
|
return sam.TCC0
|
||||||
|
case PA23:
|
||||||
|
return sam.TCC0
|
||||||
|
case PA22:
|
||||||
|
return sam.TCC0
|
||||||
|
case PB31:
|
||||||
|
return sam.TCC4
|
||||||
|
default:
|
||||||
|
return nil // not supported on this pin
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,21 +16,8 @@ const (
|
|||||||
PB5
|
PB5
|
||||||
)
|
)
|
||||||
|
|
||||||
// Configure sets the pin to input or output.
|
// getPortMask returns the PORTx register and mask for the pin.
|
||||||
func (p Pin) Configure(config PinConfig) {
|
|
||||||
if config.Mode == PinOutput { // set output bit
|
|
||||||
avr.DDRB.SetBits(1 << uint8(p))
|
|
||||||
} else { // configure input: clear output bit
|
|
||||||
avr.DDRB.ClearBits(1 << uint8(p))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
|
||||||
|
// Very simple for the attiny85, which only has a single port.
|
||||||
return avr.PORTB, 1 << uint8(p)
|
return avr.PORTB, 1 << uint8(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the current value of a GPIO pin.
|
|
||||||
func (p Pin) Get() bool {
|
|
||||||
val := avr.PINB.Get() & (1 << uint8(p))
|
|
||||||
return (val > 0)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,15 +5,76 @@ package machine
|
|||||||
import (
|
import (
|
||||||
"device/avr"
|
"device/avr"
|
||||||
"runtime/volatile"
|
"runtime/volatile"
|
||||||
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PinMode uint8
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PinInput PinMode = iota
|
PinInput PinMode = iota
|
||||||
|
PinInputPullup
|
||||||
PinOutput
|
PinOutput
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// In all the AVRs I've looked at, the PIN/DDR/PORT registers followed a regular
|
||||||
|
// pattern: PINx, DDRx, PORTx in this order without registers in between.
|
||||||
|
// Therefore, if you know any of them, you can calculate the other two.
|
||||||
|
//
|
||||||
|
// For now, I've chosen to let the PORTx register be the one that is returned
|
||||||
|
// for each specific chip and to calculate the others from that one. Setting an
|
||||||
|
// output port (done using PORTx) is likely the most common operation and the
|
||||||
|
// one that is the most time critical. For others, the PINx and DDRx register
|
||||||
|
// can trivially be calculated using a subtraction.
|
||||||
|
|
||||||
|
// Configure sets the pin to input or output.
|
||||||
|
func (p Pin) Configure(config PinConfig) {
|
||||||
|
port, mask := p.getPortMask()
|
||||||
|
// The DDRx register can be found by subtracting one from the PORTx
|
||||||
|
// register, as this appears to be the case for many (most? all?) AVR chips.
|
||||||
|
ddr := (*volatile.Register8)(unsafe.Pointer(uintptr(unsafe.Pointer(port)) - 1))
|
||||||
|
if config.Mode == PinOutput {
|
||||||
|
// set output bit
|
||||||
|
ddr.SetBits(mask)
|
||||||
|
|
||||||
|
// Note: if the pin was PinInputPullup before, it'll now be high.
|
||||||
|
// Otherwise it will be low.
|
||||||
|
} else {
|
||||||
|
// configure input: clear output bit
|
||||||
|
ddr.ClearBits(mask)
|
||||||
|
|
||||||
|
if config.Mode == PinInput {
|
||||||
|
// No pullup (floating).
|
||||||
|
// The transition may be one of the following:
|
||||||
|
// output high -> input pullup -> input (safe: output high and input pullup are similar)
|
||||||
|
// output low -> input -> input (safe: no extra transition)
|
||||||
|
port.ClearBits(mask)
|
||||||
|
} else {
|
||||||
|
// Pullup.
|
||||||
|
// The transition may be one of the following:
|
||||||
|
// output high -> input pullup -> input pullup (safe: no extra transition)
|
||||||
|
// output low -> input -> input pullup (possibly problematic)
|
||||||
|
// For the last transition (output low -> input -> input pullup),
|
||||||
|
// the transition may be problematic in some cases because there is
|
||||||
|
// an intermediate floating state (which may cause irratic
|
||||||
|
// interrupts, for example). If this is a problem, the application
|
||||||
|
// should set the pin high before configuring it as PinInputPullup.
|
||||||
|
// We can't do that here because setting it to high as an
|
||||||
|
// intermediate state may have other problems.
|
||||||
|
port.SetBits(mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the current value of a GPIO pin.
|
||||||
|
func (p Pin) Get() bool {
|
||||||
|
port, mask := p.getPortMask()
|
||||||
|
// As noted above, the PINx register is always two registers below the PORTx
|
||||||
|
// register, so we can find it simply by subtracting two from the PORTx
|
||||||
|
// register address.
|
||||||
|
pin := (*volatile.Register8)(unsafe.Pointer(uintptr(unsafe.Pointer(port)) - 2)) // PINA, PINB, etc
|
||||||
|
return (pin.Get() & mask) > 0
|
||||||
|
}
|
||||||
|
|
||||||
// Set changes the value of the GPIO pin. The pin must be configured as output.
|
// Set changes the value of the GPIO pin. The pin must be configured as output.
|
||||||
func (p Pin) Set(value bool) {
|
func (p Pin) Set(value bool) {
|
||||||
if value { // set bits
|
if value { // set bits
|
||||||
|
|||||||
@@ -48,7 +48,6 @@ func (p Pin) Set(high bool) {
|
|||||||
// Get returns the current value of a GPIO pin.
|
// Get returns the current value of a GPIO pin.
|
||||||
func (p Pin) Get() bool {
|
func (p Pin) Get() bool {
|
||||||
val := sifive.GPIO0.VALUE.Get() & (1 << uint8(p))
|
val := sifive.GPIO0.VALUE.Get() & (1 << uint8(p))
|
||||||
println(sifive.GPIO0.VALUE.Get())
|
|
||||||
return (val > 0)
|
return (val > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,7 +90,8 @@ func InitPWM() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure configures a PWM pin for output.
|
// Configure configures a PWM pin for output.
|
||||||
func (pwm PWM) Configure() {
|
func (pwm PWM) Configure() error {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set turns on the duty cycle for a PWM pin using the provided value.
|
// Set turns on the duty cycle for a PWM pin using the provided value.
|
||||||
|
|||||||
@@ -21,6 +21,18 @@ const (
|
|||||||
PinOutput PinMode = (nrf.GPIO_PIN_CNF_DIR_Output << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Disconnect << nrf.GPIO_PIN_CNF_INPUT_Pos)
|
PinOutput PinMode = (nrf.GPIO_PIN_CNF_DIR_Output << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Disconnect << nrf.GPIO_PIN_CNF_INPUT_Pos)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PinChange uint8
|
||||||
|
|
||||||
|
// Pin change interrupt constants for SetInterrupt.
|
||||||
|
const (
|
||||||
|
PinRising PinChange = nrf.GPIOTE_CONFIG_POLARITY_LoToHi
|
||||||
|
PinFalling PinChange = nrf.GPIOTE_CONFIG_POLARITY_HiToLo
|
||||||
|
PinToggle PinChange = nrf.GPIOTE_CONFIG_POLARITY_Toggle
|
||||||
|
)
|
||||||
|
|
||||||
|
// Callbacks to be called for pins configured with SetInterrupt.
|
||||||
|
var pinCallbacks [len(nrf.GPIOTE.CONFIG)]func(Pin)
|
||||||
|
|
||||||
// Configure this pin with the given configuration.
|
// Configure this pin with the given configuration.
|
||||||
func (p Pin) Configure(config PinConfig) {
|
func (p Pin) Configure(config PinConfig) {
|
||||||
cfg := config.Mode | nrf.GPIO_PIN_CNF_DRIVE_S0S1 | nrf.GPIO_PIN_CNF_SENSE_Disabled
|
cfg := config.Mode | nrf.GPIO_PIN_CNF_DRIVE_S0S1 | nrf.GPIO_PIN_CNF_SENSE_Disabled
|
||||||
@@ -59,6 +71,65 @@ func (p Pin) Get() bool {
|
|||||||
return (port.IN.Get()>>pin)&1 != 0
|
return (port.IN.Get()>>pin)&1 != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetInterrupt sets an interrupt to be executed when a particular pin changes
|
||||||
|
// state.
|
||||||
|
//
|
||||||
|
// This call will replace a previously set callback on this pin. You can pass a
|
||||||
|
// nil func to unset the pin change interrupt. If you do so, the change
|
||||||
|
// parameter is ignored and can be set to any value (such as 0).
|
||||||
|
func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) error {
|
||||||
|
// Some variables to easily check whether a channel was already configured
|
||||||
|
// as an event channel for the given pin.
|
||||||
|
// This is not just an optimization, this is requred: the datasheet says
|
||||||
|
// that configuring more than one channel for a given pin results in
|
||||||
|
// unpredictable behavior.
|
||||||
|
expectedConfigMask := uint32(nrf.GPIOTE_CONFIG_MODE_Msk | nrf.GPIOTE_CONFIG_PSEL_Msk)
|
||||||
|
expectedConfig := nrf.GPIOTE_CONFIG_MODE_Event<<nrf.GPIOTE_CONFIG_MODE_Pos | uint32(p)<<nrf.GPIOTE_CONFIG_PSEL_Pos
|
||||||
|
|
||||||
|
foundChannel := false
|
||||||
|
for i := range nrf.GPIOTE.CONFIG {
|
||||||
|
config := nrf.GPIOTE.CONFIG[i].Get()
|
||||||
|
if config == 0 || config&expectedConfigMask == expectedConfig {
|
||||||
|
// Found an empty GPIOTE channel or one that was already configured
|
||||||
|
// for this pin.
|
||||||
|
if callback == nil {
|
||||||
|
// Disable this channel.
|
||||||
|
nrf.GPIOTE.INTENCLR.Set(uint32(1 << uint(i)))
|
||||||
|
pinCallbacks[i] = nil
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Enable this channel with the given callback.
|
||||||
|
nrf.GPIOTE.INTENCLR.Set(uint32(1 << uint(i)))
|
||||||
|
nrf.GPIOTE.CONFIG[i].Set(nrf.GPIOTE_CONFIG_MODE_Event<<nrf.GPIOTE_CONFIG_MODE_Pos |
|
||||||
|
uint32(p)<<nrf.GPIOTE_CONFIG_PSEL_Pos |
|
||||||
|
uint32(change)<<nrf.GPIOTE_CONFIG_POLARITY_Pos)
|
||||||
|
pinCallbacks[i] = callback
|
||||||
|
nrf.GPIOTE.INTENSET.Set(uint32(1 << uint(i)))
|
||||||
|
foundChannel = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !foundChannel {
|
||||||
|
return ErrNoPinChangeChannel
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set and enable the GPIOTE interrupt. It's not a problem if this happens
|
||||||
|
// more than once.
|
||||||
|
interrupt.New(nrf.IRQ_GPIOTE, func(interrupt.Interrupt) {
|
||||||
|
for i := range nrf.GPIOTE.EVENTS_IN {
|
||||||
|
if nrf.GPIOTE.EVENTS_IN[i].Get() != 0 {
|
||||||
|
nrf.GPIOTE.EVENTS_IN[i].Set(0)
|
||||||
|
pin := Pin((nrf.GPIOTE.CONFIG[i].Get() & nrf.GPIOTE_CONFIG_PSEL_Msk) >> nrf.GPIOTE_CONFIG_PSEL_Pos)
|
||||||
|
pinCallbacks[i](pin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).Enable()
|
||||||
|
|
||||||
|
// Everything was configured correctly.
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// UART on the NRF.
|
// UART on the NRF.
|
||||||
type UART struct {
|
type UART struct {
|
||||||
Buffer *RingBuffer
|
Buffer *RingBuffer
|
||||||
@@ -372,13 +443,13 @@ func (spi SPI) Tx(w, r []byte) error {
|
|||||||
spi.Bus.TXD.Set(uint32(b))
|
spi.Bus.TXD.Set(uint32(b))
|
||||||
for spi.Bus.EVENTS_READY.Get() == 0 {
|
for spi.Bus.EVENTS_READY.Get() == 0 {
|
||||||
}
|
}
|
||||||
_ = spi.Bus.RXD.Get()
|
|
||||||
spi.Bus.EVENTS_READY.Set(0)
|
spi.Bus.EVENTS_READY.Set(0)
|
||||||
|
_ = spi.Bus.RXD.Get()
|
||||||
}
|
}
|
||||||
for spi.Bus.EVENTS_READY.Get() == 0 {
|
for spi.Bus.EVENTS_READY.Get() == 0 {
|
||||||
}
|
}
|
||||||
_ = spi.Bus.RXD.Get()
|
|
||||||
spi.Bus.EVENTS_READY.Set(0)
|
spi.Bus.EVENTS_READY.Set(0)
|
||||||
|
_ = spi.Bus.RXD.Get()
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// write/read
|
// write/read
|
||||||
|
|||||||
@@ -159,7 +159,8 @@ func InitPWM() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure configures a PWM pin for output.
|
// Configure configures a PWM pin for output.
|
||||||
func (pwm PWM) Configure() {
|
func (pwm PWM) Configure() error {
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set turns on the duty cycle for a PWM pin using the provided value.
|
// Set turns on the duty cycle for a PWM pin using the provided value.
|
||||||
|
|||||||
@@ -104,8 +104,8 @@ func InitADC() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Configure configures an ADC pin to be able to read analog data.
|
// Configure configures an ADC pin to be able to read analog data.
|
||||||
func (a ADC) Configure() {
|
func (a ADC) Configure() error {
|
||||||
return // no pin specific setup on nrf52840 machine.
|
return nil // no pin specific setup on nrf52840 machine.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns the current value of a ADC pin in the range 0..0xffff.
|
// Get returns the current value of a ADC pin in the range 0..0xffff.
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package os
|
||||||
|
|
||||||
|
func Getenv(key string) string {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
package os
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalid = errors.New("invalid argument")
|
||||||
|
ErrPermission = errors.New("permission denied")
|
||||||
|
ErrClosed = errors.New("file already closed")
|
||||||
|
|
||||||
|
// Portable analogs of some common system call errors.
|
||||||
|
// Note that these are exported for use in the Filesystem interface.
|
||||||
|
ErrUnsupported = errors.New("operation not supported")
|
||||||
|
ErrNotImplemented = errors.New("operation not implemented")
|
||||||
|
ErrNotExist = errors.New("file not found")
|
||||||
|
ErrExist = errors.New("file exists")
|
||||||
|
)
|
||||||
|
|
||||||
|
func IsPermission(err error) bool {
|
||||||
|
return err == ErrPermission
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSyscallError(syscall string, err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &SyscallError{syscall, err}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SyscallError records an error from a specific system call.
|
||||||
|
type SyscallError struct {
|
||||||
|
Syscall string
|
||||||
|
Err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() }
|
||||||
|
|
||||||
|
func (e *SyscallError) Unwrap() error { return e.Err }
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package os
|
||||||
|
|
||||||
|
type Signal interface {
|
||||||
|
String() string
|
||||||
|
Signal() // to distinguish from other Stringers
|
||||||
|
}
|
||||||
+108
-58
@@ -6,53 +6,132 @@
|
|||||||
package os
|
package os
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Portable analogs of some common system call errors.
|
// Mkdir creates a directory. If the operation fails, it will return an error of
|
||||||
var (
|
// type *PathError.
|
||||||
errUnsupported = errors.New("operation not supported")
|
func Mkdir(path string, perm FileMode) error {
|
||||||
notImplemented = errors.New("os: not implemented")
|
fs, suffix := findMount(path)
|
||||||
)
|
if fs == nil {
|
||||||
|
return &PathError{"mkdir", path, ErrNotExist}
|
||||||
|
}
|
||||||
|
err := fs.Mkdir(suffix, perm)
|
||||||
|
if err != nil {
|
||||||
|
return &PathError{"mkdir", path, err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
|
// Remove removes a file or (empty) directory. If the operation fails, it will
|
||||||
// standard output, and standard error file descriptors.
|
// return an error of type *PathError.
|
||||||
var (
|
func Remove(path string) error {
|
||||||
Stdin = &File{0, "/dev/stdin"}
|
fs, suffix := findMount(path)
|
||||||
Stdout = &File{1, "/dev/stdout"}
|
if fs == nil {
|
||||||
Stderr = &File{2, "/dev/stderr"}
|
return &PathError{"remove", path, ErrNotExist}
|
||||||
)
|
}
|
||||||
|
err := fs.Remove(suffix)
|
||||||
|
if err != nil {
|
||||||
|
return &PathError{"remove", path, err}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// File represents an open file descriptor.
|
// File represents an open file descriptor.
|
||||||
type File struct {
|
type File struct {
|
||||||
fd uintptr
|
handle FileHandle
|
||||||
name string
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Name returns the name of the file with which it was opened.
|
||||||
|
func (f *File) Name() string {
|
||||||
|
return f.name
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpenFile opens the named file. If the operation fails, the returned error
|
||||||
|
// will be of type *PathError.
|
||||||
|
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
|
||||||
|
fs, suffix := findMount(name)
|
||||||
|
if fs == nil {
|
||||||
|
return nil, &PathError{"open", name, ErrNotExist}
|
||||||
|
}
|
||||||
|
handle, err := fs.OpenFile(suffix, flag, perm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &PathError{"open", name, err}
|
||||||
|
}
|
||||||
|
return &File{name: name, handle: handle}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open opens the file named for reading.
|
||||||
|
func Open(name string) (*File, error) {
|
||||||
|
return OpenFile(name, O_RDONLY, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates the named file, overwriting it if it already exists.
|
||||||
|
func Create(name string) (*File, error) {
|
||||||
|
return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read reads up to len(b) bytes from the File. It returns the number of bytes
|
||||||
|
// read and any error encountered. At end of file, Read returns 0, io.EOF.
|
||||||
|
func (f *File) Read(b []byte) (n int, err error) {
|
||||||
|
n, err = f.handle.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
err = &PathError{"read", f.name, err}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f *File) ReadAt(b []byte, off int64) (n int, err error) {
|
||||||
|
return 0, ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write writes len(b) bytes to the File. It returns the number of bytes written
|
||||||
|
// and an error, if any. Write returns a non-nil error when n != len(b).
|
||||||
|
func (f *File) Write(b []byte) (n int, err error) {
|
||||||
|
n, err = f.handle.Write(b)
|
||||||
|
if err != nil {
|
||||||
|
err = &PathError{"write", f.name, err}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close closes the File, rendering it unusable for I/O.
|
||||||
|
func (f *File) Close() (err error) {
|
||||||
|
err = f.handle.Close()
|
||||||
|
if err != nil {
|
||||||
|
err = &PathError{"close", f.name, err}
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Readdir is a stub, not yet implemented
|
// Readdir is a stub, not yet implemented
|
||||||
func (f *File) Readdir(n int) ([]FileInfo, error) {
|
func (f *File) Readdir(n int) ([]FileInfo, error) {
|
||||||
return nil, notImplemented
|
return nil, &PathError{"readdir", f.name, ErrNotImplemented}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Readdirnames is a stub, not yet implemented
|
// Readdirnames is a stub, not yet implemented
|
||||||
func (f *File) Readdirnames(n int) (names []string, err error) {
|
func (f *File) Readdirnames(n int) (names []string, err error) {
|
||||||
return nil, notImplemented
|
return nil, &PathError{"readdirnames", f.name, ErrNotImplemented}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stat is a stub, not yet implemented
|
// Stat is a stub, not yet implemented
|
||||||
func (f *File) Stat() (FileInfo, error) {
|
func (f *File) Stat() (FileInfo, error) {
|
||||||
return nil, notImplemented
|
return nil, &PathError{"stat", f.name, ErrNotImplemented}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFile returns a new File with the given file descriptor and name.
|
// Sync is a stub, not yet implemented
|
||||||
func NewFile(fd uintptr, name string) *File {
|
func (f *File) Sync() error {
|
||||||
return &File{fd, name}
|
return ErrNotImplemented
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fd returns the integer Unix file descriptor referencing the open file. The
|
func (f *File) SyscallConn() (syscall.RawConn, error) {
|
||||||
// file descriptor is valid only until f.Close is called.
|
return nil, ErrNotImplemented
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fd returns the file handle referencing the open file.
|
||||||
func (f *File) Fd() uintptr {
|
func (f *File) Fd() uintptr {
|
||||||
return f.fd
|
panic("unimplemented: os.file.Fd()")
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -72,32 +151,8 @@ type PathError struct {
|
|||||||
Err error
|
Err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() }
|
func (e *PathError) Error() string {
|
||||||
|
return e.Op + " " + e.Path + ": " + e.Err.Error()
|
||||||
// Open is a super simple stub function (for now), only capable of opening stdin, stdout, and stderr
|
|
||||||
func Open(name string) (*File, error) {
|
|
||||||
fd := uintptr(999)
|
|
||||||
switch name {
|
|
||||||
case "/dev/stdin":
|
|
||||||
fd = 0
|
|
||||||
case "/dev/stdout":
|
|
||||||
fd = 1
|
|
||||||
case "/dev/stderr":
|
|
||||||
fd = 2
|
|
||||||
default:
|
|
||||||
return nil, &PathError{"open", name, notImplemented}
|
|
||||||
}
|
|
||||||
return &File{fd, name}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OpenFile is a stub, passing through to the stub Open() call
|
|
||||||
func OpenFile(name string, flag int, perm FileMode) (*File, error) {
|
|
||||||
return Open(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create is a stub, passing through to the stub Open() call
|
|
||||||
func Create(name string) (*File, error) {
|
|
||||||
return Open(name)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type FileMode uint32
|
type FileMode uint32
|
||||||
@@ -148,19 +203,19 @@ type FileInfo interface {
|
|||||||
Name() string // base name of the file
|
Name() string // base name of the file
|
||||||
Size() int64 // length in bytes for regular files; system-dependent for others
|
Size() int64 // length in bytes for regular files; system-dependent for others
|
||||||
Mode() FileMode // file mode bits
|
Mode() FileMode // file mode bits
|
||||||
// ModTime() time.Time // modification time
|
// TODO ModTime() time.Time // modification time
|
||||||
IsDir() bool // abbreviation for Mode().IsDir()
|
IsDir() bool // abbreviation for Mode().IsDir()
|
||||||
Sys() interface{} // underlying data source (can return nil)
|
Sys() interface{} // underlying data source (can return nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stat is a stub, not yet implemented
|
// Stat is a stub, not yet implemented
|
||||||
func Stat(name string) (FileInfo, error) {
|
func Stat(name string) (FileInfo, error) {
|
||||||
return nil, notImplemented
|
return nil, &PathError{"stat", name, ErrNotImplemented}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lstat is a stub, not yet implemented
|
// Lstat is a stub, not yet implemented
|
||||||
func Lstat(name string) (FileInfo, error) {
|
func Lstat(name string) (FileInfo, error) {
|
||||||
return nil, notImplemented
|
return nil, &PathError{"lstat", name, ErrNotImplemented}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getwd is a stub (for now), always returning an empty string
|
// Getwd is a stub (for now), always returning an empty string
|
||||||
@@ -178,11 +233,6 @@ func TempDir() string {
|
|||||||
return "/tmp"
|
return "/tmp"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mkdir is a stub, not yet implemented
|
|
||||||
func Mkdir(name string, perm FileMode) error {
|
|
||||||
return notImplemented
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsExist is a stub (for now), always returning false
|
// IsExist is a stub (for now), always returning false
|
||||||
func IsExist(err error) bool {
|
func IsExist(err error) bool {
|
||||||
return false
|
return false
|
||||||
|
|||||||
+24
-8
@@ -6,28 +6,44 @@ import (
|
|||||||
_ "unsafe"
|
_ "unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
|
||||||
|
// standard output, and standard error file descriptors.
|
||||||
|
var (
|
||||||
|
Stdin = &File{stdioFileHandle(0), "/dev/stdin"}
|
||||||
|
Stdout = &File{stdioFileHandle(1), "/dev/stdout"}
|
||||||
|
Stderr = &File{stdioFileHandle(2), "/dev/stderr"}
|
||||||
|
)
|
||||||
|
|
||||||
|
// isOS indicates whether we're running on a real operating system with
|
||||||
|
// filesystem support.
|
||||||
|
const isOS = false
|
||||||
|
|
||||||
|
// stdioFileHandle represents one of stdin, stdout, or stderr depending on the
|
||||||
|
// number. It implements the FileHandle interface.
|
||||||
|
type stdioFileHandle uint8
|
||||||
|
|
||||||
// Read is unsupported on this system.
|
// Read is unsupported on this system.
|
||||||
func (f *File) Read(b []byte) (n int, err error) {
|
func (f stdioFileHandle) Read(b []byte) (n int, err error) {
|
||||||
return 0, errUnsupported
|
return 0, ErrUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write writes len(b) bytes to the output. It returns the number of bytes
|
// Write writes len(b) bytes to the output. It returns the number of bytes
|
||||||
// written or an error if this file is not stdout or stderr.
|
// written or an error if this file is not stdout or stderr.
|
||||||
func (f *File) Write(b []byte) (n int, err error) {
|
func (f stdioFileHandle) Write(b []byte) (n int, err error) {
|
||||||
switch f.fd {
|
switch f {
|
||||||
case Stdout.fd, Stderr.fd:
|
case 1, 2: // stdout, stderr
|
||||||
for _, c := range b {
|
for _, c := range b {
|
||||||
putchar(c)
|
putchar(c)
|
||||||
}
|
}
|
||||||
return len(b), nil
|
return len(b), nil
|
||||||
default:
|
default:
|
||||||
return 0, errUnsupported
|
return 0, ErrUnsupported
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close is unsupported on this system.
|
// Close is unsupported on this system.
|
||||||
func (f *File) Close() error {
|
func (f stdioFileHandle) Close() error {
|
||||||
return errUnsupported
|
return ErrUnsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:linkname putchar runtime.putchar
|
//go:linkname putchar runtime.putchar
|
||||||
|
|||||||
+92
-6
@@ -6,19 +6,105 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
// Mount the host filesystem at the root directory. This is what most
|
||||||
|
// programs will be expecting.
|
||||||
|
Mount("/", unixFilesystem{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stdin, Stdout, and Stderr are open Files pointing to the standard input,
|
||||||
|
// standard output, and standard error file descriptors.
|
||||||
|
var (
|
||||||
|
Stdin = &File{unixFileHandle(0), "/dev/stdin"}
|
||||||
|
Stdout = &File{unixFileHandle(1), "/dev/stdout"}
|
||||||
|
Stderr = &File{unixFileHandle(2), "/dev/stderr"}
|
||||||
|
)
|
||||||
|
|
||||||
|
// isOS indicates whether we're running on a real operating system with
|
||||||
|
// filesystem support.
|
||||||
|
const isOS = true
|
||||||
|
|
||||||
|
// unixFilesystem is an empty handle for a Unix/Linux filesystem. All operations
|
||||||
|
// are relative to the current working directory.
|
||||||
|
type unixFilesystem struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs unixFilesystem) Mkdir(path string, perm FileMode) error {
|
||||||
|
return handleSyscallError(syscall.Mkdir(path, uint32(perm)))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs unixFilesystem) Remove(path string) error {
|
||||||
|
return handleSyscallError(syscall.Unlink(path))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs unixFilesystem) OpenFile(path string, flag int, perm FileMode) (FileHandle, error) {
|
||||||
|
// Map os package flags to syscall flags.
|
||||||
|
syscallFlag := 0
|
||||||
|
if flag&O_RDONLY != 0 {
|
||||||
|
syscallFlag |= syscall.O_RDONLY
|
||||||
|
}
|
||||||
|
if flag&O_WRONLY != 0 {
|
||||||
|
syscallFlag |= syscall.O_WRONLY
|
||||||
|
}
|
||||||
|
if flag&O_RDWR != 0 {
|
||||||
|
syscallFlag |= syscall.O_RDWR
|
||||||
|
}
|
||||||
|
if flag&O_APPEND != 0 {
|
||||||
|
syscallFlag |= syscall.O_APPEND
|
||||||
|
}
|
||||||
|
if flag&O_CREATE != 0 {
|
||||||
|
syscallFlag |= syscall.O_CREAT
|
||||||
|
}
|
||||||
|
if flag&O_EXCL != 0 {
|
||||||
|
syscallFlag |= syscall.O_EXCL
|
||||||
|
}
|
||||||
|
if flag&O_SYNC != 0 {
|
||||||
|
syscallFlag |= syscall.O_SYNC
|
||||||
|
}
|
||||||
|
if flag&O_TRUNC != 0 {
|
||||||
|
syscallFlag |= syscall.O_TRUNC
|
||||||
|
}
|
||||||
|
fp, err := syscall.Open(path, syscallFlag, uint32(perm))
|
||||||
|
return unixFileHandle(fp), handleSyscallError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// unixFileHandle is a Unix file pointer with associated methods that implement
|
||||||
|
// the FileHandle interface.
|
||||||
|
type unixFileHandle uintptr
|
||||||
|
|
||||||
// Read reads up to len(b) bytes from the File. It returns the number of bytes
|
// Read reads up to len(b) bytes from the File. It returns the number of bytes
|
||||||
// read and any error encountered. At end of file, Read returns 0, io.EOF.
|
// read and any error encountered. At end of file, Read returns 0, io.EOF.
|
||||||
func (f *File) Read(b []byte) (n int, err error) {
|
func (f unixFileHandle) Read(b []byte) (n int, err error) {
|
||||||
return syscall.Read(int(f.fd), b)
|
n, err = syscall.Read(int(f), b)
|
||||||
|
err = handleSyscallError(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write writes len(b) bytes to the File. It returns the number of bytes written
|
// Write writes len(b) bytes to the File. It returns the number of bytes written
|
||||||
// and an error, if any. Write returns a non-nil error when n != len(b).
|
// and an error, if any. Write returns a non-nil error when n != len(b).
|
||||||
func (f *File) Write(b []byte) (n int, err error) {
|
func (f unixFileHandle) Write(b []byte) (n int, err error) {
|
||||||
return syscall.Write(int(f.fd), b)
|
n, err = syscall.Write(int(f), b)
|
||||||
|
err = handleSyscallError(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the File, rendering it unusable for I/O.
|
// Close closes the File, rendering it unusable for I/O.
|
||||||
func (f *File) Close() error {
|
func (f unixFileHandle) Close() error {
|
||||||
return syscall.Close(int(f.fd))
|
return handleSyscallError(syscall.Close(int(f)))
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleSyscallError converts syscall errors into regular os package errors.
|
||||||
|
// The err parameter must be either nil or of type syscall.Errno.
|
||||||
|
func handleSyscallError(err error) error {
|
||||||
|
if err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch err.(syscall.Errno) {
|
||||||
|
case syscall.EEXIST:
|
||||||
|
return ErrExist
|
||||||
|
case syscall.ENOENT:
|
||||||
|
return ErrNotExist
|
||||||
|
default:
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
package os
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// mounts lists the mount points currently mounted in the filesystem provided by
|
||||||
|
// the os package. To resolve a path to a mount point, it is scanned from top to
|
||||||
|
// bottom looking for the first prefix match.
|
||||||
|
var mounts []mountPoint
|
||||||
|
|
||||||
|
type mountPoint struct {
|
||||||
|
// prefix is a filesystem prefix, that always starts and ends with a forward
|
||||||
|
// slash. To denote the root filesystem, use a single slash: "/".
|
||||||
|
// This allows fast checking whether a path lies within a mount point.
|
||||||
|
prefix string
|
||||||
|
|
||||||
|
// filesystem is the Filesystem implementation that is mounted at this mount
|
||||||
|
// point.
|
||||||
|
filesystem Filesystem
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filesystem provides an interface for generic filesystem drivers mounted in
|
||||||
|
// the os package. The errors returned must be one of the os.Err* errors, or a
|
||||||
|
// custom error if one doesn't exist. It should not be a *PathError because
|
||||||
|
// errors will be wrapped with a *PathError by the filesystem abstraction.
|
||||||
|
//
|
||||||
|
// WARNING: this interface is not finalized and may change in a future version.
|
||||||
|
type Filesystem interface {
|
||||||
|
// OpenFile opens the named file.
|
||||||
|
OpenFile(name string, flag int, perm FileMode) (FileHandle, error)
|
||||||
|
|
||||||
|
// Mkdir creates a new directoy with the specified permission (before
|
||||||
|
// umask). Some filesystems may not support directories or permissions.
|
||||||
|
Mkdir(name string, perm FileMode) error
|
||||||
|
|
||||||
|
// Remove removes the named file or (empty) directory.
|
||||||
|
Remove(name string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// FileHandle is an interface that should be implemented by filesystems
|
||||||
|
// implementing the Filesystem interface.
|
||||||
|
//
|
||||||
|
// WARNING: this interface is not finalized and may change in a future version.
|
||||||
|
type FileHandle interface {
|
||||||
|
// Read reads up to len(b) bytes from the file.
|
||||||
|
Read(b []byte) (n int, err error)
|
||||||
|
|
||||||
|
// Write writes up to len(b) bytes to the file.
|
||||||
|
Write(b []byte) (n int, err error)
|
||||||
|
|
||||||
|
// Close closes the file, making it unusable for further writes.
|
||||||
|
Close() (err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// findMount returns the appropriate (mounted) filesystem to use for a given
|
||||||
|
// filename plus the path relative to that filesystem.
|
||||||
|
func findMount(path string) (Filesystem, string) {
|
||||||
|
for i := len(mounts) - 1; i >= 0; i-- {
|
||||||
|
mount := mounts[i]
|
||||||
|
if strings.HasPrefix(path, mount.prefix) {
|
||||||
|
return mount.filesystem, path[len(mount.prefix)-1:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isOS {
|
||||||
|
// Assume that the first entry in the mounts slice is the OS filesystem
|
||||||
|
// at the root of the directory tree. Use it as-is, to support relative
|
||||||
|
// paths.
|
||||||
|
return mounts[0].filesystem, path
|
||||||
|
}
|
||||||
|
return nil, path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mount mounts the given filesystem in the filesystem abstraction layer of the
|
||||||
|
// os package. It is not possible to unmount filesystems. Filesystems added
|
||||||
|
// later will override earlier filesystems.
|
||||||
|
//
|
||||||
|
// The provided prefix must start and end with a forward slash. This is true for
|
||||||
|
// the root directory ("/") for example.
|
||||||
|
func Mount(prefix string, filesystem Filesystem) {
|
||||||
|
if prefix[0] != '/' || prefix[len(prefix)-1] != '/' {
|
||||||
|
panic("os.Mount: invalid prefix")
|
||||||
|
}
|
||||||
|
mounts = append(mounts, mountPoint{prefix, filesystem})
|
||||||
|
}
|
||||||
@@ -9,6 +9,15 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Args hold the command-line arguments, starting with the program name.
|
||||||
|
var Args []string
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
Args = runtime_args()
|
||||||
|
}
|
||||||
|
|
||||||
|
func runtime_args() []string // in package runtime
|
||||||
|
|
||||||
// Exit causes the current program to exit with the given status code.
|
// Exit causes the current program to exit with the given status code.
|
||||||
// Conventionally, code zero indicates success, non-zero an error.
|
// Conventionally, code zero indicates success, non-zero an error.
|
||||||
// The program terminates immediately; deferred functions are not run.
|
// The program terminates immediately; deferred functions are not run.
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package os
|
||||||
|
|
||||||
|
func Hostname() (name string, err error) {
|
||||||
|
return "", ErrNotImplemented
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package reflect
|
||||||
|
|
||||||
|
func DeepEqual(x, y interface{}) bool {
|
||||||
|
if x == nil || y == nil {
|
||||||
|
return x == y
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("unimplemented: reflect.DeepEqual()")
|
||||||
|
}
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package reflect
|
||||||
|
|
||||||
|
import (
|
||||||
|
"unicode/utf8"
|
||||||
|
)
|
||||||
|
|
||||||
|
// errSyntax indicates that a value does not have the right syntax for the target type.
|
||||||
|
var errSyntax = badSyntax{}
|
||||||
|
|
||||||
|
type badSyntax struct{}
|
||||||
|
|
||||||
|
func (badSyntax) Error() string {
|
||||||
|
return "invalid syntax"
|
||||||
|
}
|
||||||
|
|
||||||
|
func unhex(b byte) (v rune, ok bool) {
|
||||||
|
c := rune(b)
|
||||||
|
switch {
|
||||||
|
case '0' <= c && c <= '9':
|
||||||
|
return c - '0', true
|
||||||
|
case 'a' <= c && c <= 'f':
|
||||||
|
return c - 'a' + 10, true
|
||||||
|
case 'A' <= c && c <= 'F':
|
||||||
|
return c - 'A' + 10, true
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// unquoteChar decodes the first character or byte in the escaped string
|
||||||
|
// or character literal represented by the string s.
|
||||||
|
// It returns four values:
|
||||||
|
//
|
||||||
|
// 1) value, the decoded Unicode code point or byte value;
|
||||||
|
// 2) multibyte, a boolean indicating whether the decoded character requires a multibyte UTF-8 representation;
|
||||||
|
// 3) tail, the remainder of the string after the character; and
|
||||||
|
// 4) an error that will be nil if the character is syntactically valid.
|
||||||
|
//
|
||||||
|
// The second argument, quote, specifies the type of literal being parsed
|
||||||
|
// and therefore which escaped quote character is permitted.
|
||||||
|
// If set to a single quote, it permits the sequence \' and disallows unescaped '.
|
||||||
|
// If set to a double quote, it permits \" and disallows unescaped ".
|
||||||
|
// If set to zero, it does not permit either escape and allows both quote characters to appear unescaped.
|
||||||
|
func unquoteChar(s string, quote byte) (value rune, multibyte bool, tail string, err error) {
|
||||||
|
// easy cases
|
||||||
|
if len(s) == 0 {
|
||||||
|
err = errSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch c := s[0]; {
|
||||||
|
case c == quote && (quote == '\'' || quote == '"'):
|
||||||
|
err = errSyntax
|
||||||
|
return
|
||||||
|
case c >= utf8.RuneSelf:
|
||||||
|
r, size := utf8.DecodeRuneInString(s)
|
||||||
|
return r, true, s[size:], nil
|
||||||
|
case c != '\\':
|
||||||
|
return rune(s[0]), false, s[1:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// hard case: c is backslash
|
||||||
|
if len(s) <= 1 {
|
||||||
|
err = errSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c := s[1]
|
||||||
|
s = s[2:]
|
||||||
|
|
||||||
|
switch c {
|
||||||
|
case 'a':
|
||||||
|
value = '\a'
|
||||||
|
case 'b':
|
||||||
|
value = '\b'
|
||||||
|
case 'f':
|
||||||
|
value = '\f'
|
||||||
|
case 'n':
|
||||||
|
value = '\n'
|
||||||
|
case 'r':
|
||||||
|
value = '\r'
|
||||||
|
case 't':
|
||||||
|
value = '\t'
|
||||||
|
case 'v':
|
||||||
|
value = '\v'
|
||||||
|
case 'x', 'u', 'U':
|
||||||
|
n := 0
|
||||||
|
switch c {
|
||||||
|
case 'x':
|
||||||
|
n = 2
|
||||||
|
case 'u':
|
||||||
|
n = 4
|
||||||
|
case 'U':
|
||||||
|
n = 8
|
||||||
|
}
|
||||||
|
var v rune
|
||||||
|
if len(s) < n {
|
||||||
|
err = errSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for j := 0; j < n; j++ {
|
||||||
|
x, ok := unhex(s[j])
|
||||||
|
if !ok {
|
||||||
|
err = errSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v = v<<4 | x
|
||||||
|
}
|
||||||
|
s = s[n:]
|
||||||
|
if c == 'x' {
|
||||||
|
// single-byte string, possibly not UTF-8
|
||||||
|
value = v
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if v > utf8.MaxRune {
|
||||||
|
err = errSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value = v
|
||||||
|
multibyte = true
|
||||||
|
case '0', '1', '2', '3', '4', '5', '6', '7':
|
||||||
|
v := rune(c) - '0'
|
||||||
|
if len(s) < 2 {
|
||||||
|
err = errSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for j := 0; j < 2; j++ { // one digit already; two more
|
||||||
|
x := rune(s[j]) - '0'
|
||||||
|
if x < 0 || x > 7 {
|
||||||
|
err = errSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v = (v << 3) | x
|
||||||
|
}
|
||||||
|
s = s[2:]
|
||||||
|
if v > 255 {
|
||||||
|
err = errSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value = v
|
||||||
|
case '\\':
|
||||||
|
value = '\\'
|
||||||
|
case '\'', '"':
|
||||||
|
if c != quote {
|
||||||
|
err = errSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value = rune(c)
|
||||||
|
default:
|
||||||
|
err = errSyntax
|
||||||
|
return
|
||||||
|
}
|
||||||
|
tail = s
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// unquote interprets s as a single-quoted, double-quoted,
|
||||||
|
// or backquoted Go string literal, returning the string value
|
||||||
|
// that s quotes. (If s is single-quoted, it would be a Go
|
||||||
|
// character literal; unquote returns the corresponding
|
||||||
|
// one-character string.)
|
||||||
|
func unquote(s string) (string, error) {
|
||||||
|
n := len(s)
|
||||||
|
if n < 2 {
|
||||||
|
return "", errSyntax
|
||||||
|
}
|
||||||
|
quote := s[0]
|
||||||
|
if quote != s[n-1] {
|
||||||
|
return "", errSyntax
|
||||||
|
}
|
||||||
|
s = s[1 : n-1]
|
||||||
|
|
||||||
|
if quote == '`' {
|
||||||
|
if contains(s, '`') {
|
||||||
|
return "", errSyntax
|
||||||
|
}
|
||||||
|
if contains(s, '\r') {
|
||||||
|
// -1 because we know there is at least one \r to remove.
|
||||||
|
buf := make([]byte, 0, len(s)-1)
|
||||||
|
for i := 0; i < len(s); i++ {
|
||||||
|
if s[i] != '\r' {
|
||||||
|
buf = append(buf, s[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(buf), nil
|
||||||
|
}
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
if quote != '"' && quote != '\'' {
|
||||||
|
return "", errSyntax
|
||||||
|
}
|
||||||
|
if contains(s, '\n') {
|
||||||
|
return "", errSyntax
|
||||||
|
}
|
||||||
|
|
||||||
|
// Is it trivial? Avoid allocation.
|
||||||
|
if !contains(s, '\\') && !contains(s, quote) {
|
||||||
|
switch quote {
|
||||||
|
case '"':
|
||||||
|
if utf8.ValidString(s) {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
case '\'':
|
||||||
|
r, size := utf8.DecodeRuneInString(s)
|
||||||
|
if size == len(s) && (r != utf8.RuneError || size != 1) {
|
||||||
|
return s, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var runeTmp [utf8.UTFMax]byte
|
||||||
|
buf := make([]byte, 0, 3*len(s)/2) // Try to avoid more allocations.
|
||||||
|
for len(s) > 0 {
|
||||||
|
c, multibyte, ss, err := unquoteChar(s, quote)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
s = ss
|
||||||
|
if c < utf8.RuneSelf || !multibyte {
|
||||||
|
buf = append(buf, byte(c))
|
||||||
|
} else {
|
||||||
|
n := utf8.EncodeRune(runeTmp[:], c)
|
||||||
|
buf = append(buf, runeTmp[:n]...)
|
||||||
|
}
|
||||||
|
if quote == '\'' && len(s) != 0 {
|
||||||
|
// single-quoted must be single character
|
||||||
|
return "", errSyntax
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return string(buf), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// contains reports whether the string contains the byte c.
|
||||||
|
func contains(s string, c byte) bool {
|
||||||
|
return indexByteString(s, c) != -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
|
||||||
|
}
|
||||||
+86
-2
@@ -1,3 +1,7 @@
|
|||||||
|
// Copyright 2009 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
package reflect
|
package reflect
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -227,7 +231,7 @@ func (t Type) Field(i int) StructField {
|
|||||||
// There is a tag.
|
// There is a tag.
|
||||||
var tagNum uintptr
|
var tagNum uintptr
|
||||||
tagNum, p = readVarint(p)
|
tagNum, p = readVarint(p)
|
||||||
field.Tag = readStringSidetable(unsafe.Pointer(&structNamesSidetable), tagNum)
|
field.Tag = StructTag(readStringSidetable(unsafe.Pointer(&structNamesSidetable), tagNum))
|
||||||
} else {
|
} else {
|
||||||
// There is no tag.
|
// There is no tag.
|
||||||
field.Tag = ""
|
field.Tag = ""
|
||||||
@@ -445,6 +449,22 @@ func (t Type) Comparable() bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t Type) ConvertibleTo(u Type) bool {
|
||||||
|
panic("unimplemented: (reflect.Type).ConvertibleTo()")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Type) NumMethod() int {
|
||||||
|
panic("unimplemented: (reflect.Type).NumMethod()")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Type) Name() string {
|
||||||
|
panic("unimplemented: (reflect.Type).Name()")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Type) Key() Type {
|
||||||
|
panic("unimplemented: (reflect.Type).Key()")
|
||||||
|
}
|
||||||
|
|
||||||
// A StructField describes a single field in a struct.
|
// A StructField describes a single field in a struct.
|
||||||
type StructField struct {
|
type StructField struct {
|
||||||
// Name indicates the field name.
|
// Name indicates the field name.
|
||||||
@@ -455,11 +475,75 @@ type StructField struct {
|
|||||||
PkgPath string
|
PkgPath string
|
||||||
|
|
||||||
Type Type
|
Type Type
|
||||||
Tag string
|
Tag StructTag // field tag string
|
||||||
Anonymous bool
|
Anonymous bool
|
||||||
Offset uintptr
|
Offset uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A StructTag is the tag string in a struct field.
|
||||||
|
type StructTag string
|
||||||
|
|
||||||
|
// TODO: it would be feasible to do the key/value splitting at compile time,
|
||||||
|
// avoiding the code size cost of doing it at runtime
|
||||||
|
|
||||||
|
// Get returns the value associated with key in the tag string.
|
||||||
|
func (tag StructTag) Get(key string) string {
|
||||||
|
v, _ := tag.Lookup(key)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup returns the value associated with key in the tag string.
|
||||||
|
func (tag StructTag) Lookup(key string) (value string, ok bool) {
|
||||||
|
for tag != "" {
|
||||||
|
// Skip leading space.
|
||||||
|
i := 0
|
||||||
|
for i < len(tag) && tag[i] == ' ' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
tag = tag[i:]
|
||||||
|
if tag == "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan to colon. A space, a quote or a control character is a syntax error.
|
||||||
|
// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
|
||||||
|
// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
|
||||||
|
// as it is simpler to inspect the tag's bytes than the tag's runes.
|
||||||
|
i = 0
|
||||||
|
for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
name := string(tag[:i])
|
||||||
|
tag = tag[i+1:]
|
||||||
|
|
||||||
|
// Scan quoted string to find value.
|
||||||
|
i = 1
|
||||||
|
for i < len(tag) && tag[i] != '"' {
|
||||||
|
if tag[i] == '\\' {
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
if i >= len(tag) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
qvalue := string(tag[:i+1])
|
||||||
|
tag = tag[i+1:]
|
||||||
|
|
||||||
|
if key == name {
|
||||||
|
value, err := unquote(qvalue)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
return value, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
// TypeError is the error that is used in a panic when invoking a method on a
|
// TypeError is the error that is used in a panic when invoking a method on a
|
||||||
// type that is not applicable to that type.
|
// type that is not applicable to that type.
|
||||||
type TypeError struct {
|
type TypeError struct {
|
||||||
|
|||||||
+68
-7
@@ -304,29 +304,48 @@ func (v Value) Slice(i, j int) Value {
|
|||||||
panic("unimplemented: (reflect.Value).Slice()")
|
panic("unimplemented: (reflect.Value).Slice()")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:linkname maplen runtime.hashmapLenUnsafePointer
|
||||||
|
func maplen(p unsafe.Pointer) int
|
||||||
|
|
||||||
|
//go:linkname chanlen runtime.chanLenUnsafePointer
|
||||||
|
func chanlen(p unsafe.Pointer) int
|
||||||
|
|
||||||
// Len returns the length of this value for slices, strings, arrays, channels,
|
// Len returns the length of this value for slices, strings, arrays, channels,
|
||||||
// and maps. For oter types, it panics.
|
// and maps. For other types, it panics.
|
||||||
func (v Value) Len() int {
|
func (v Value) Len() int {
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
|
case Array:
|
||||||
|
return v.Type().Len()
|
||||||
|
case Chan:
|
||||||
|
return chanlen(v.value)
|
||||||
|
case Map:
|
||||||
|
return maplen(v.value)
|
||||||
case Slice:
|
case Slice:
|
||||||
return int((*SliceHeader)(v.value).Len)
|
return int((*SliceHeader)(v.value).Len)
|
||||||
case String:
|
case String:
|
||||||
return int((*StringHeader)(v.value).Len)
|
return int((*StringHeader)(v.value).Len)
|
||||||
case Array:
|
default:
|
||||||
return v.Type().Len()
|
panic(&ValueError{"Len"})
|
||||||
default: // Chan, Map
|
|
||||||
panic("unimplemented: (reflect.Value).Len()")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:linkname chancap runtime.chanCapUnsafePointer
|
||||||
|
func chancap(p unsafe.Pointer) int
|
||||||
|
|
||||||
|
// Cap returns the capacity of this value for arrays, channels and slices.
|
||||||
|
// For other types, it panics.
|
||||||
func (v Value) Cap() int {
|
func (v Value) Cap() int {
|
||||||
t := v.Type()
|
t := v.Type()
|
||||||
switch t.Kind() {
|
switch t.Kind() {
|
||||||
|
case Array:
|
||||||
|
return v.Type().Len()
|
||||||
|
case Chan:
|
||||||
|
return chancap(v.value)
|
||||||
case Slice:
|
case Slice:
|
||||||
return int((*SliceHeader)(v.value).Cap)
|
return int((*SliceHeader)(v.value).Cap)
|
||||||
default: // Array, Chan
|
default:
|
||||||
panic("unimplemented: (reflect.Value).Cap()")
|
panic(&ValueError{"Cap"})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,6 +661,18 @@ func (v Value) checkAddressable() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v Value) OverflowInt(x int64) bool {
|
||||||
|
panic("unimplemented: reflect.OverflowInt()")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Value) OverflowUint(x uint64) bool {
|
||||||
|
panic("unimplemented: reflect.OverflowUint()")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Value) Convert(t Type) Value {
|
||||||
|
panic("unimplemented: (reflect.Value).Convert()")
|
||||||
|
}
|
||||||
|
|
||||||
func MakeSlice(typ Type, len, cap int) Value {
|
func MakeSlice(typ Type, len, cap int) Value {
|
||||||
panic("unimplemented: reflect.MakeSlice()")
|
panic("unimplemented: reflect.MakeSlice()")
|
||||||
}
|
}
|
||||||
@@ -681,3 +712,33 @@ func (e *ValueError) Error() string {
|
|||||||
// Calls to this function are converted to LLVM intrinsic calls such as
|
// Calls to this function are converted to LLVM intrinsic calls such as
|
||||||
// llvm.memcpy.p0i8.p0i8.i32().
|
// llvm.memcpy.p0i8.p0i8.i32().
|
||||||
func memcpy(dst, src unsafe.Pointer, size uintptr)
|
func memcpy(dst, src unsafe.Pointer, size uintptr)
|
||||||
|
|
||||||
|
// Copy copies the contents of src into dst until either
|
||||||
|
// dst has been filled or src has been exhausted.
|
||||||
|
func Copy(dst, src Value) int {
|
||||||
|
panic("unimplemented: reflect.Copy()")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Append appends the values x to a slice s and returns the resulting slice.
|
||||||
|
// As in Go, each x's value must be assignable to the slice's element type.
|
||||||
|
func Append(s Value, x ...Value) Value {
|
||||||
|
panic("unimplemented: reflect.Append()")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Value) SetMapIndex(key, elem Value) {
|
||||||
|
panic("unimplemented: (reflect.Value).SetMapIndex()")
|
||||||
|
}
|
||||||
|
|
||||||
|
// FieldByIndex returns the nested field corresponding to index.
|
||||||
|
func (v Value) FieldByIndex(index []int) Value {
|
||||||
|
panic("unimplemented: (reflect.Value).FieldByIndex()")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v Value) FieldByName(name string) Value {
|
||||||
|
panic("unimplemented: (reflect.Value).FieldByName()")
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeMap creates a new map with the specified type.
|
||||||
|
func MakeMap(typ Type) Value {
|
||||||
|
panic("unimplemented: reflect.MakeMap()")
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,3 +19,86 @@ func align(ptr uintptr) uintptr {
|
|||||||
func getCurrentStackPointer() uintptr {
|
func getCurrentStackPointer() uintptr {
|
||||||
return arm.AsmFull("mov {}, sp", nil)
|
return arm.AsmFull("mov {}, sp", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Documentation:
|
||||||
|
// * https://llvm.org/docs/Atomics.html
|
||||||
|
// * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html
|
||||||
|
//
|
||||||
|
// In the case of Cortex-M, some atomic operations are emitted inline while
|
||||||
|
// others are emitted as libcalls. How many are emitted as libcalls depends on
|
||||||
|
// the MCU core variant (M3 and higher support some 32-bit atomic operations
|
||||||
|
// while M0 and M0+ do not).
|
||||||
|
|
||||||
|
//export __sync_fetch_and_add_4
|
||||||
|
func __sync_fetch_and_add_4(ptr *uint32, value uint32) uint32 {
|
||||||
|
mask := arm.DisableInterrupts()
|
||||||
|
oldValue := *ptr
|
||||||
|
*ptr = oldValue + value
|
||||||
|
arm.EnableInterrupts(mask)
|
||||||
|
return oldValue
|
||||||
|
}
|
||||||
|
|
||||||
|
//export __sync_fetch_and_add_8
|
||||||
|
func __sync_fetch_and_add_8(ptr *uint64, value uint64) uint64 {
|
||||||
|
mask := arm.DisableInterrupts()
|
||||||
|
oldValue := *ptr
|
||||||
|
*ptr = oldValue + value
|
||||||
|
arm.EnableInterrupts(mask)
|
||||||
|
return oldValue
|
||||||
|
}
|
||||||
|
|
||||||
|
//export __sync_lock_test_and_set_4
|
||||||
|
func __sync_lock_test_and_set_4(ptr *uint32, value uint32) uint32 {
|
||||||
|
mask := arm.DisableInterrupts()
|
||||||
|
oldValue := *ptr
|
||||||
|
*ptr = value
|
||||||
|
arm.EnableInterrupts(mask)
|
||||||
|
return oldValue
|
||||||
|
}
|
||||||
|
|
||||||
|
//export __sync_lock_test_and_set_8
|
||||||
|
func __sync_lock_test_and_set_8(ptr *uint64, value uint64) uint64 {
|
||||||
|
mask := arm.DisableInterrupts()
|
||||||
|
oldValue := *ptr
|
||||||
|
*ptr = value
|
||||||
|
arm.EnableInterrupts(mask)
|
||||||
|
return oldValue
|
||||||
|
}
|
||||||
|
|
||||||
|
//export __sync_val_compare_and_swap_4
|
||||||
|
func __sync_val_compare_and_swap_4(ptr *uint32, expected, desired uint32) uint32 {
|
||||||
|
mask := arm.DisableInterrupts()
|
||||||
|
oldValue := *ptr
|
||||||
|
if oldValue == expected {
|
||||||
|
*ptr = desired
|
||||||
|
}
|
||||||
|
arm.EnableInterrupts(mask)
|
||||||
|
return oldValue
|
||||||
|
}
|
||||||
|
|
||||||
|
//export __sync_val_compare_and_swap_8
|
||||||
|
func __sync_val_compare_and_swap_8(ptr *uint64, expected, desired uint64) uint64 {
|
||||||
|
mask := arm.DisableInterrupts()
|
||||||
|
oldValue := *ptr
|
||||||
|
if oldValue == expected {
|
||||||
|
*ptr = desired
|
||||||
|
}
|
||||||
|
arm.EnableInterrupts(mask)
|
||||||
|
return oldValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// The safest thing to do here would just be to disable interrupts for
|
||||||
|
// procPin/procUnpin. Note that a global variable is safe in this case, as any
|
||||||
|
// access to procPinnedMask will happen with interrupts disabled.
|
||||||
|
|
||||||
|
var procPinnedMask uintptr
|
||||||
|
|
||||||
|
//go:linkname procPin sync/atomic.runtime_procPin
|
||||||
|
func procPin() {
|
||||||
|
procPinnedMask = arm.DisableInterrupts()
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname procUnpin sync/atomic.runtime_procUnpin
|
||||||
|
func procUnpin() {
|
||||||
|
arm.EnableInterrupts(procPinnedMask)
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,3 +17,76 @@ func align(ptr uintptr) uintptr {
|
|||||||
func getCurrentStackPointer() uintptr {
|
func getCurrentStackPointer() uintptr {
|
||||||
return riscv.AsmFull("mv {}, sp", nil)
|
return riscv.AsmFull("mv {}, sp", nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Documentation:
|
||||||
|
// * https://llvm.org/docs/Atomics.html
|
||||||
|
// * https://gcc.gnu.org/onlinedocs/gcc/_005f_005fsync-Builtins.html
|
||||||
|
//
|
||||||
|
// In the case of RISC-V, some operations may be implemented with libcalls if
|
||||||
|
// the operation is too big to be handled by assembly. Officially, these calls
|
||||||
|
// should be implemented with a lock-free algorithm but as (as of this time) all
|
||||||
|
// supported RISC-V chips have a single hart, we can simply disable interrupts
|
||||||
|
// to get the same behavior.
|
||||||
|
|
||||||
|
//export __atomic_load_8
|
||||||
|
func __atomic_load_8(ptr *uint64, ordering int32) uint64 {
|
||||||
|
mask := riscv.DisableInterrupts()
|
||||||
|
value := *ptr
|
||||||
|
riscv.EnableInterrupts(mask)
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
//export __atomic_store_8
|
||||||
|
func __atomic_store_8(ptr *uint64, value uint64, ordering int32) {
|
||||||
|
mask := riscv.DisableInterrupts()
|
||||||
|
*ptr = value
|
||||||
|
riscv.EnableInterrupts(mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export __atomic_exchange_8
|
||||||
|
func __atomic_exchange_8(ptr *uint64, value uint64, ordering int32) uint64 {
|
||||||
|
mask := riscv.DisableInterrupts()
|
||||||
|
oldValue := *ptr
|
||||||
|
*ptr = value
|
||||||
|
riscv.EnableInterrupts(mask)
|
||||||
|
return oldValue
|
||||||
|
}
|
||||||
|
|
||||||
|
//export __atomic_compare_exchange_8
|
||||||
|
func __atomic_compare_exchange_8(ptr, expected *uint64, desired uint64, success_ordering, failure_ordering int32) bool {
|
||||||
|
mask := riscv.DisableInterrupts()
|
||||||
|
oldValue := *ptr
|
||||||
|
success := oldValue == *expected
|
||||||
|
if success {
|
||||||
|
*ptr = desired
|
||||||
|
} else {
|
||||||
|
*expected = oldValue
|
||||||
|
}
|
||||||
|
riscv.EnableInterrupts(mask)
|
||||||
|
return success
|
||||||
|
}
|
||||||
|
|
||||||
|
//export __atomic_fetch_add_8
|
||||||
|
func __atomic_fetch_add_8(ptr *uint64, value uint64, ordering int32) uint64 {
|
||||||
|
mask := riscv.DisableInterrupts()
|
||||||
|
oldValue := *ptr
|
||||||
|
*ptr = oldValue + value
|
||||||
|
riscv.EnableInterrupts(mask)
|
||||||
|
return oldValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// The safest thing to do here would just be to disable interrupts for
|
||||||
|
// procPin/procUnpin. Note that a global variable is safe in this case, as any
|
||||||
|
// access to procPinnedMask will happen with interrupts disabled.
|
||||||
|
|
||||||
|
var procPinnedMask uintptr
|
||||||
|
|
||||||
|
//go:linkname procPin sync/atomic.runtime_procPin
|
||||||
|
func procPin() {
|
||||||
|
procPinnedMask = riscv.DisableInterrupts()
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:linkname procUnpin sync/atomic.runtime_procUnpin
|
||||||
|
func procUnpin() {
|
||||||
|
riscv.EnableInterrupts(procPinnedMask)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
package runtime
|
|
||||||
|
|
||||||
// This file contains implementations for the sync/atomic package.
|
|
||||||
|
|
||||||
// All implementations assume there are no goroutines, threads or interrupts.
|
|
||||||
|
|
||||||
//go:linkname loadUint64 sync/atomic.LoadUint64
|
|
||||||
func loadUint64(addr *uint64) uint64 {
|
|
||||||
return *addr
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:linkname storeUint32 sync/atomic.StoreUint32
|
|
||||||
func storeUint32(addr *uint32, val uint32) {
|
|
||||||
*addr = val
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:linkname compareAndSwapUint64 sync/atomic.CompareAndSwapUint64
|
|
||||||
func compareAndSwapUint64(addr *uint64, old, new uint64) bool {
|
|
||||||
if *addr == old {
|
|
||||||
*addr = new
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package runtime
|
|
||||||
|
|
||||||
//go:linkname indexBytePortable internal/bytealg.IndexByte
|
|
||||||
func indexBytePortable(s []byte, c byte) int {
|
|
||||||
for i, b := range s {
|
|
||||||
if b == c {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
+38
-4
@@ -136,6 +136,38 @@ func chanMake(elementSize uintptr, bufSize uintptr) *channel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return the number of entries in this chan, called from the len builtin.
|
||||||
|
// A nil chan is defined as having length 0.
|
||||||
|
//go:inline
|
||||||
|
func chanLen(c *channel) int {
|
||||||
|
if c == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return int(c.bufUsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrapper for use in reflect
|
||||||
|
func chanLenUnsafePointer(p unsafe.Pointer) int {
|
||||||
|
c := (*channel)(p)
|
||||||
|
return chanLen(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the capacity of this chan, called from the cap builtin.
|
||||||
|
// A nil chan is defined as having capacity 0.
|
||||||
|
//go:inline
|
||||||
|
func chanCap(c *channel) int {
|
||||||
|
if c == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return int(c.bufSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wrapper for use in reflect
|
||||||
|
func chanCapUnsafePointer(p unsafe.Pointer) int {
|
||||||
|
c := (*channel)(p)
|
||||||
|
return chanCap(c)
|
||||||
|
}
|
||||||
|
|
||||||
// resumeRX resumes the next receiver and returns the destination pointer.
|
// resumeRX resumes the next receiver and returns the destination pointer.
|
||||||
// If the ok value is true, then the caller is expected to store a value into this pointer.
|
// If the ok value is true, then the caller is expected to store a value into this pointer.
|
||||||
func (ch *channel) resumeRX(ok bool) unsafe.Pointer {
|
func (ch *channel) resumeRX(ok bool) unsafe.Pointer {
|
||||||
@@ -414,7 +446,7 @@ type chanSelectState struct {
|
|||||||
// chanSend sends a single value over the channel.
|
// chanSend sends a single value over the channel.
|
||||||
// This operation will block unless a value is immediately available.
|
// This operation will block unless a value is immediately available.
|
||||||
// May panic if the channel is closed.
|
// May panic if the channel is closed.
|
||||||
func chanSend(ch *channel, value unsafe.Pointer) {
|
func chanSend(ch *channel, value unsafe.Pointer, blockedlist *channelBlockedList) {
|
||||||
if ch.trySend(value) {
|
if ch.trySend(value) {
|
||||||
// value immediately sent
|
// value immediately sent
|
||||||
chanDebug(ch)
|
chanDebug(ch)
|
||||||
@@ -430,10 +462,11 @@ func chanSend(ch *channel, value unsafe.Pointer) {
|
|||||||
sender := task.Current()
|
sender := task.Current()
|
||||||
ch.state = chanStateSend
|
ch.state = chanStateSend
|
||||||
sender.Ptr = value
|
sender.Ptr = value
|
||||||
ch.blocked = &channelBlockedList{
|
*blockedlist = channelBlockedList{
|
||||||
next: ch.blocked,
|
next: ch.blocked,
|
||||||
t: sender,
|
t: sender,
|
||||||
}
|
}
|
||||||
|
ch.blocked = blockedlist
|
||||||
chanDebug(ch)
|
chanDebug(ch)
|
||||||
task.Pause()
|
task.Pause()
|
||||||
sender.Ptr = nil
|
sender.Ptr = nil
|
||||||
@@ -443,7 +476,7 @@ func chanSend(ch *channel, value unsafe.Pointer) {
|
|||||||
// It blocks if there is no available value to recieve.
|
// It blocks if there is no available value to recieve.
|
||||||
// The recieved value is copied into the value pointer.
|
// The recieved value is copied into the value pointer.
|
||||||
// Returns the comma-ok value.
|
// Returns the comma-ok value.
|
||||||
func chanRecv(ch *channel, value unsafe.Pointer) bool {
|
func chanRecv(ch *channel, value unsafe.Pointer, blockedlist *channelBlockedList) bool {
|
||||||
if rx, ok := ch.tryRecv(value); rx {
|
if rx, ok := ch.tryRecv(value); rx {
|
||||||
// value immediately available
|
// value immediately available
|
||||||
chanDebug(ch)
|
chanDebug(ch)
|
||||||
@@ -459,10 +492,11 @@ func chanRecv(ch *channel, value unsafe.Pointer) bool {
|
|||||||
receiver := task.Current()
|
receiver := task.Current()
|
||||||
ch.state = chanStateRecv
|
ch.state = chanStateRecv
|
||||||
receiver.Ptr, receiver.Data = value, 1
|
receiver.Ptr, receiver.Data = value, 1
|
||||||
ch.blocked = &channelBlockedList{
|
*blockedlist = channelBlockedList{
|
||||||
next: ch.blocked,
|
next: ch.blocked,
|
||||||
t: receiver,
|
t: receiver,
|
||||||
}
|
}
|
||||||
|
ch.blocked = blockedlist
|
||||||
chanDebug(ch)
|
chanDebug(ch)
|
||||||
task.Pause()
|
task.Pause()
|
||||||
ok := receiver.Data == 1
|
ok := receiver.Data == 1
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package runtime
|
||||||
|
|
||||||
|
// The Error interface identifies a run time error.
|
||||||
|
type Error interface {
|
||||||
|
error
|
||||||
|
|
||||||
|
RuntimeError()
|
||||||
|
}
|
||||||
@@ -602,3 +602,11 @@ func alloc(size uintptr) unsafe.Pointer {
|
|||||||
func free(ptr unsafe.Pointer) {
|
func free(ptr unsafe.Pointer) {
|
||||||
// Currently unimplemented due to bugs in coroutine lowering.
|
// Currently unimplemented due to bugs in coroutine lowering.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func KeepAlive(x interface{}) {
|
||||||
|
// Unimplemented. Only required with SetFinalizer().
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetFinalizer(obj interface{}, finalizer interface{}) {
|
||||||
|
// Unimplemented.
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
// This is a hashmap implementation for the map[T]T type.
|
// This is a hashmap implementation for the map[T]T type.
|
||||||
// It is very rougly based on the implementation of the Go hashmap:
|
// It is very roughly based on the implementation of the Go hashmap:
|
||||||
//
|
//
|
||||||
// https://golang.org/src/runtime/map.go
|
// https://golang.org/src/runtime/map.go
|
||||||
|
|
||||||
@@ -80,6 +80,7 @@ func hashmapMake(keySize, valueSize uint8, sizeHint uintptr) *hashmap {
|
|||||||
|
|
||||||
// Return the number of entries in this hashmap, called from the len builtin.
|
// Return the number of entries in this hashmap, called from the len builtin.
|
||||||
// A nil hashmap is defined as having length 0.
|
// A nil hashmap is defined as having length 0.
|
||||||
|
//go:inline
|
||||||
func hashmapLen(m *hashmap) int {
|
func hashmapLen(m *hashmap) int {
|
||||||
if m == nil {
|
if m == nil {
|
||||||
return 0
|
return 0
|
||||||
@@ -87,6 +88,12 @@ func hashmapLen(m *hashmap) int {
|
|||||||
return int(m.count)
|
return int(m.count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrapper for use in reflect
|
||||||
|
func hashmapLenUnsafePointer(p unsafe.Pointer) int {
|
||||||
|
m := (*hashmap)(p)
|
||||||
|
return hashmapLen(m)
|
||||||
|
}
|
||||||
|
|
||||||
// Set a specified key to a given value. Grow the map if necessary.
|
// Set a specified key to a given value. Grow the map if necessary.
|
||||||
//go:nobounds
|
//go:nobounds
|
||||||
func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) {
|
func hashmapSet(m *hashmap, key unsafe.Pointer, value unsafe.Pointer, hash uint32, keyEqual func(x, y unsafe.Pointer, n uintptr) bool) {
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
// +build avr
|
||||||
|
|
||||||
|
package interrupt
|
||||||
|
|
||||||
|
import "device"
|
||||||
|
|
||||||
|
// State represents the previous global interrupt state.
|
||||||
|
type State uint8
|
||||||
|
|
||||||
|
// Disable disables all interrupts and returns the previous interrupt state. It
|
||||||
|
// can be used in a critical section like this:
|
||||||
|
//
|
||||||
|
// state := interrupt.Disable()
|
||||||
|
// // critical section
|
||||||
|
// interrupt.Restore(state)
|
||||||
|
//
|
||||||
|
// Critical sections can be nested. Make sure to call Restore in the same order
|
||||||
|
// as you called Disable (this happens naturally with the pattern above).
|
||||||
|
func Disable() (state State) {
|
||||||
|
// SREG is at I/O address 0x3f.
|
||||||
|
return State(device.AsmFull(`
|
||||||
|
in {}, 0x3f
|
||||||
|
cli
|
||||||
|
`, nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore restores interrupts to what they were before. Give the previous state
|
||||||
|
// returned by Disable as a parameter. If interrupts were disabled before
|
||||||
|
// calling Disable, this will not re-enable interrupts, allowing for nested
|
||||||
|
// cricital sections.
|
||||||
|
func Restore(state State) {
|
||||||
|
// SREG is at I/O address 0x3f.
|
||||||
|
device.AsmFull("out 0x3f, {state}", map[string]interface{}{
|
||||||
|
"state": state,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -21,3 +21,27 @@ func (irq Interrupt) Enable() {
|
|||||||
func (irq Interrupt) SetPriority(priority uint8) {
|
func (irq Interrupt) SetPriority(priority uint8) {
|
||||||
arm.SetPriority(uint32(irq.num), uint32(priority))
|
arm.SetPriority(uint32(irq.num), uint32(priority))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// State represents the previous global interrupt state.
|
||||||
|
type State uintptr
|
||||||
|
|
||||||
|
// Disable disables all interrupts and returns the previous interrupt state. It
|
||||||
|
// can be used in a critical section like this:
|
||||||
|
//
|
||||||
|
// state := interrupt.Disable()
|
||||||
|
// // critical section
|
||||||
|
// interrupt.Restore(state)
|
||||||
|
//
|
||||||
|
// Critical sections can be nested. Make sure to call Restore in the same order
|
||||||
|
// as you called Disable (this happens naturally with the pattern above).
|
||||||
|
func Disable() (state State) {
|
||||||
|
return State(arm.DisableInterrupts())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore restores interrupts to what they were before. Give the previous state
|
||||||
|
// returned by Disable as a parameter. If interrupts were disabled before
|
||||||
|
// calling Disable, this will not re-enable interrupts, allowing for nested
|
||||||
|
// cricital sections.
|
||||||
|
func Restore(state State) {
|
||||||
|
arm.EnableInterrupts(uintptr(state))
|
||||||
|
}
|
||||||
|
|||||||
@@ -34,3 +34,32 @@ func handleInterrupt() {
|
|||||||
// appropriate interrupt handler for the given interrupt ID.
|
// appropriate interrupt handler for the given interrupt ID.
|
||||||
//go:linkname callInterruptHandler runtime.callInterruptHandler
|
//go:linkname callInterruptHandler runtime.callInterruptHandler
|
||||||
func callInterruptHandler(id int)
|
func callInterruptHandler(id int)
|
||||||
|
|
||||||
|
// State represents the previous global interrupt state.
|
||||||
|
type State uint8
|
||||||
|
|
||||||
|
// Disable disables all interrupts and returns the previous interrupt state. It
|
||||||
|
// can be used in a critical section like this:
|
||||||
|
//
|
||||||
|
// state := interrupt.Disable()
|
||||||
|
// // critical section
|
||||||
|
// interrupt.Restore(state)
|
||||||
|
//
|
||||||
|
// Critical sections can be nested. Make sure to call Restore in the same order
|
||||||
|
// as you called Disable (this happens naturally with the pattern above).
|
||||||
|
func Disable() (state State) {
|
||||||
|
// Save the previous interrupt state.
|
||||||
|
state = State(regInterruptMasterEnable.Get())
|
||||||
|
// Disable all interrupts.
|
||||||
|
regInterruptMasterEnable.Set(0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore restores interrupts to what they were before. Give the previous state
|
||||||
|
// returned by Disable as a parameter. If interrupts were disabled before
|
||||||
|
// calling Disable, this will not re-enable interrupts, allowing for nested
|
||||||
|
// cricital sections.
|
||||||
|
func Restore(state State) {
|
||||||
|
// Restore interrupts to the previous state.
|
||||||
|
regInterruptMasterEnable.Set(uint16(state))
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
// +build tinygo.riscv
|
||||||
|
|
||||||
|
package interrupt
|
||||||
|
|
||||||
|
import "device/riscv"
|
||||||
|
|
||||||
|
// State represents the previous global interrupt state.
|
||||||
|
type State uintptr
|
||||||
|
|
||||||
|
// Disable disables all interrupts and returns the previous interrupt state. It
|
||||||
|
// can be used in a critical section like this:
|
||||||
|
//
|
||||||
|
// state := interrupt.Disable()
|
||||||
|
// // critical section
|
||||||
|
// interrupt.Restore(state)
|
||||||
|
//
|
||||||
|
// Critical sections can be nested. Make sure to call Restore in the same order
|
||||||
|
// as you called Disable (this happens naturally with the pattern above).
|
||||||
|
func Disable() (state State) {
|
||||||
|
return State(riscv.DisableInterrupts())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore restores interrupts to what they were before. Give the previous state
|
||||||
|
// returned by Disable as a parameter. If interrupts were disabled before
|
||||||
|
// calling Disable, this will not re-enable interrupts, allowing for nested
|
||||||
|
// cricital sections.
|
||||||
|
func Restore(state State) {
|
||||||
|
riscv.EnableInterrupts(uintptr(state))
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user