mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-02 01:57:48 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a3f96b221 |
+10
-10
@@ -294,16 +294,16 @@ commands:
|
|||||||
variant: "macos"
|
variant: "macos"
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- go-cache-macos-v3-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
- go-cache-macos-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
|
||||||
- go-cache-macos-v3-{{ checksum "go.mod" }}
|
- go-cache-macos-v2-{{ checksum "go.mod" }}
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- llvm-source-11-macos-v3
|
- llvm-source-11-macos-v2
|
||||||
- run:
|
- run:
|
||||||
name: "Fetch LLVM source"
|
name: "Fetch LLVM source"
|
||||||
command: make llvm-source
|
command: make llvm-source
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: llvm-source-11-macos-v3
|
key: llvm-source-11-macos-v2
|
||||||
paths:
|
paths:
|
||||||
- llvm-project/clang/lib/Headers
|
- llvm-project/clang/lib/Headers
|
||||||
- llvm-project/clang/include
|
- llvm-project/clang/include
|
||||||
@@ -311,7 +311,7 @@ commands:
|
|||||||
- llvm-project/llvm/include
|
- llvm-project/llvm/include
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- llvm-build-11-macos-v4
|
- llvm-build-11-macos-v3
|
||||||
- run:
|
- run:
|
||||||
name: "Build LLVM"
|
name: "Build LLVM"
|
||||||
command: |
|
command: |
|
||||||
@@ -327,17 +327,17 @@ commands:
|
|||||||
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
|
||||||
fi
|
fi
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: llvm-build-11-macos-v4
|
key: llvm-build-11-macos-v3
|
||||||
paths:
|
paths:
|
||||||
llvm-build
|
llvm-build
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
keys:
|
keys:
|
||||||
- wasi-libc-sysroot-macos-v4
|
- wasi-libc-sysroot-macos-v3
|
||||||
- run:
|
- run:
|
||||||
name: "Build wasi-libc"
|
name: "Build wasi-libc"
|
||||||
command: make wasi-libc
|
command: make wasi-libc
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: wasi-libc-sysroot-macos-v4
|
key: wasi-libc-sysroot-macos-v3
|
||||||
paths:
|
paths:
|
||||||
- lib/wasi-libc/sysroot
|
- lib/wasi-libc/sysroot
|
||||||
- run:
|
- run:
|
||||||
@@ -359,7 +359,7 @@ commands:
|
|||||||
tinygo version
|
tinygo version
|
||||||
- run: make smoketest AVR=0
|
- run: make smoketest AVR=0
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: go-cache-macos-v3-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
key: go-cache-macos-v2-{{ checksum "go.mod" }}-{{ .Environment.CIRCLE_BUILD_NUM }}
|
||||||
paths:
|
paths:
|
||||||
- ~/.cache/go-build
|
- ~/.cache/go-build
|
||||||
- /go/pkg/mod
|
- /go/pkg/mod
|
||||||
@@ -401,7 +401,7 @@ jobs:
|
|||||||
- build-linux
|
- build-linux
|
||||||
build-macos:
|
build-macos:
|
||||||
macos:
|
macos:
|
||||||
xcode: "11.1.0" # macOS 10.14
|
xcode: "10.1.0"
|
||||||
steps:
|
steps:
|
||||||
- build-macos
|
- build-macos
|
||||||
|
|
||||||
|
|||||||
-122
@@ -1,125 +1,3 @@
|
|||||||
0.18.0
|
|
||||||
---
|
|
||||||
|
|
||||||
* **command line**
|
|
||||||
- drop support for Go 1.11 and 1.12
|
|
||||||
- throw an error when no target is specified on Windows
|
|
||||||
- improve error messages in `getDefaultPort()`, support for multiple ports
|
|
||||||
- remove `-cflags` and `-ldflags` flags
|
|
||||||
- implement `-ldflags="-X ..."`
|
|
||||||
- add `-print-allocs` flag that lets you print all heap allocations
|
|
||||||
- openocd commands in tinygo command line
|
|
||||||
- add `-llvm-features` parameter
|
|
||||||
- match `go test` output
|
|
||||||
- discover USB ports only, this will ignore f.ex. bluetooth
|
|
||||||
- use physicmal path instead of cached GOROOT in function getGoroot
|
|
||||||
- add goroot for snap installs
|
|
||||||
* **compiler**
|
|
||||||
- `builder`: add support for `-opt=0`
|
|
||||||
- `builder`, `compiler`: compile and cache packages in parallel
|
|
||||||
- `builder`: run interp per package
|
|
||||||
- `builder`: cache C and assembly file outputs
|
|
||||||
- `builder`: add support for `-x` flag to print commands
|
|
||||||
- `builder`: add optsize attribute while building the package
|
|
||||||
- `builder`: run function passes per package
|
|
||||||
- `builder`: hard code Clang compiler
|
|
||||||
- `compiler`: do not use `llvm.GlobalContext()`
|
|
||||||
- `compiler`: remove SimpleDCE pass
|
|
||||||
- `compiler`: do not emit nil checks for `*ssa.Alloc` instructions
|
|
||||||
- `compiler`: merge `runtime.typecodeID` and runtime.typeInInterface
|
|
||||||
- `compiler`: do not check for impossible type asserts
|
|
||||||
- `compiler`: fix use of global context: `llvm.Int32Type()`
|
|
||||||
- `compiler`: add interface IR test
|
|
||||||
- `compiler`: fix lack of method name in interface matching
|
|
||||||
- `compiler`: fix "fragment covers entire variable" bug
|
|
||||||
- `compiler`: optimize string literals and globals
|
|
||||||
- `compiler`: decouple func lowering from interface type codes
|
|
||||||
- `compiler`: add function attributes to some runtime calls
|
|
||||||
- `compiler`: improve position information in error messages
|
|
||||||
- `cgo`: add support for CFLAGS in .c files
|
|
||||||
- `interp`: support GEP on fixed (MMIO) addresses
|
|
||||||
- `interp`: handle `(reflect.Type).Elem()`
|
|
||||||
- `interp`: add support for runtime.interfaceMethod
|
|
||||||
- `interp`: make toLLVMValue return an error instead of panicking
|
|
||||||
- `interp`: add support for switch statement
|
|
||||||
- `interp`: fix phi instruction
|
|
||||||
- `interp`: remove map support
|
|
||||||
- `interp`: support extractvalue/insertvalue with multiple operands
|
|
||||||
- `transform`: optimize string comparisons against ""
|
|
||||||
- `transform`: optimize `reflect.Type` `Implements()` method
|
|
||||||
- `transform`: fix bug in interface lowering when signatures are renamed
|
|
||||||
- `transform`: don't rely on struct name of `runtime.typecodeID`
|
|
||||||
- `transform`: use IPSCCP pass instead of the constant propagation pass
|
|
||||||
- `transform`: fix func lowering assertion failure
|
|
||||||
- `transform`: do not lower zero-sized alloc to alloca
|
|
||||||
- `transform`: split interface and reflect lowering
|
|
||||||
* **standard library**
|
|
||||||
- `runtime`: add dummy debug package
|
|
||||||
- `machine`: fix data shift/mask in newUSBSetup
|
|
||||||
- `machine`: make `machine.I2C0` and similar objects pointers
|
|
||||||
- `machine`: unify usbcdc code
|
|
||||||
- `machine`: refactor PWM support
|
|
||||||
- `machine`: avoid heap allocations in USB code
|
|
||||||
- `reflect`: let `reflect.Type` be of interface type
|
|
||||||
- `reflect`: implement a number of stub functions
|
|
||||||
- `reflect`: check for access in the `Interface` method call
|
|
||||||
- `reflect`: fix `AssignableTo` and `Implements` methods
|
|
||||||
- `reflect`: implement `Value.CanAddr`
|
|
||||||
- `reflect`: implement `Sizeof` and `Alignof` for func values
|
|
||||||
- `reflect`: implement `New` function
|
|
||||||
- `runtime`: implement command line arguments in hosted environments
|
|
||||||
- `runtime`: implement environment variables for Linux
|
|
||||||
- `runtime`: improve timers on nrf, and samd chips
|
|
||||||
* **targets**
|
|
||||||
- all: use -Qunused-arguments only for assembly files
|
|
||||||
- `atmega1280`: add PWM support
|
|
||||||
- `attiny`: remove dummy UART
|
|
||||||
- `atsamd21`: improve SPI
|
|
||||||
- `atsamd51`: fix PWM support in atsamd51p20
|
|
||||||
- `atsamd5x`: improve SPI
|
|
||||||
- `atsamd51`, `atsame5x`: unify samd51 and same5x
|
|
||||||
- `atsamd51`, `atsamd21`: fix `ADC.Get()` value at 8bit and 10bit
|
|
||||||
- `atsame5x`: add support for CAN
|
|
||||||
- `avr`: remove I2C stubs from attiny support
|
|
||||||
- `cortexm`: check for `arm-none-eabi-gdb` and `gdb-multiarch` commands
|
|
||||||
- `cortexm`: add `__isr_vector` symbol
|
|
||||||
- `cortexm`: disable FPU on Cortex-M4
|
|
||||||
- `cortexm`: clean up Cortex-M target files
|
|
||||||
- `fe310`: fix SPI read
|
|
||||||
- `gameboy-advance`: Fix RGBA color interpretation
|
|
||||||
- `nrf52833`: add PWM support
|
|
||||||
- `stm32l0`: use unified UART logic
|
|
||||||
- `stm32`: move f103 (bluepill) to common i2c code
|
|
||||||
- `stm32`: separate altfunc selection for UART Tx/Rx
|
|
||||||
- `stm32`: i2c implementation for F7, L5 and L4 MCUs
|
|
||||||
- `stm32`: make SPI CLK fast to fix data issue
|
|
||||||
- `stm32`: support SPI on L4 series
|
|
||||||
- `unix`: avoid possible heap allocation with `-opt=0`
|
|
||||||
- `unix`: use conservative GC by default
|
|
||||||
- `unix`: use the tasks scheduler instead of coroutines
|
|
||||||
- `wasi`: upgrade WASI version to wasi_snapshot_preview1
|
|
||||||
- `wasi`: darwin: support basic file io based on libc
|
|
||||||
- `wasm`: only export explicitly exported functions
|
|
||||||
- `wasm`: use WASI ABI for exit function
|
|
||||||
- `wasm`: scan globals conservatively
|
|
||||||
* **boards**
|
|
||||||
- `arduino-mega1280`: add support for the Arduino Mega 1280
|
|
||||||
- `arduino-nano-new`: Add Arduino Nano w/ New Bootloader target
|
|
||||||
- `atsame54-xpro`: add initial support this board
|
|
||||||
- `feather-m4-can`: add initial support for this board
|
|
||||||
- `grandcentral-m4`: add board support for Adafruit Grand Central M4 (SAMD51)
|
|
||||||
- `lgt92`: update to new UART structure
|
|
||||||
- `microbit`: remove LED constant
|
|
||||||
- `microbit-v2`: add support for S113 SoftDevice
|
|
||||||
- `nucleol432`: add support for this board
|
|
||||||
- `nucleo-l031k6`: add this board
|
|
||||||
- `pca10059`: initial support for this board
|
|
||||||
- `qtpy`: fix msd-volume-name
|
|
||||||
- `qtpy`: fix i2c setting
|
|
||||||
- `teensy40`: move txBuffer allocation to UART declaration
|
|
||||||
- `teensy40`: add UART0 as alias for UART1
|
|
||||||
|
|
||||||
|
|
||||||
0.17.0
|
0.17.0
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -182,28 +182,25 @@ tinygo:
|
|||||||
test: wasi-libc
|
test: wasi-libc
|
||||||
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test -v -buildmode exe -tags byollvm ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test -v -buildmode exe -tags byollvm ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
|
||||||
|
|
||||||
TEST_PACKAGES = \
|
|
||||||
container/heap \
|
|
||||||
container/list \
|
|
||||||
container/ring \
|
|
||||||
crypto/des \
|
|
||||||
encoding \
|
|
||||||
encoding/ascii85 \
|
|
||||||
encoding/base32 \
|
|
||||||
encoding/hex \
|
|
||||||
hash/adler32 \
|
|
||||||
hash/fnv \
|
|
||||||
hash/crc64 \
|
|
||||||
math \
|
|
||||||
math/cmplx \
|
|
||||||
text/scanner \
|
|
||||||
unicode/utf8 \
|
|
||||||
|
|
||||||
# Test known-working standard library packages.
|
# Test known-working standard library packages.
|
||||||
# TODO: parallelize, and only show failing tests (no implied -v flag).
|
# TODO: do this in one command, parallelize, and only show failing tests (no
|
||||||
|
# implied -v flag).
|
||||||
.PHONY: tinygo-test
|
.PHONY: tinygo-test
|
||||||
tinygo-test:
|
tinygo-test:
|
||||||
$(TINYGO) test $(TEST_PACKAGES)
|
$(TINYGO) test container/heap
|
||||||
|
$(TINYGO) test container/list
|
||||||
|
$(TINYGO) test container/ring
|
||||||
|
$(TINYGO) test crypto/des
|
||||||
|
$(TINYGO) test encoding/ascii85
|
||||||
|
$(TINYGO) test encoding/base32
|
||||||
|
$(TINYGO) test encoding/hex
|
||||||
|
$(TINYGO) test hash/adler32
|
||||||
|
$(TINYGO) test hash/fnv
|
||||||
|
$(TINYGO) test hash/crc64
|
||||||
|
$(TINYGO) test math
|
||||||
|
$(TINYGO) test math/cmplx
|
||||||
|
$(TINYGO) test text/scanner
|
||||||
|
$(TINYGO) test unicode/utf8
|
||||||
|
|
||||||
.PHONY: smoketest
|
.PHONY: smoketest
|
||||||
smoketest:
|
smoketest:
|
||||||
@@ -343,12 +340,8 @@ smoketest:
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=atsame54-xpro examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=atsame54-xpro examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=atsame54-xpro examples/can
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-m4-can examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=feather-m4-can examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-m4-can examples/caninterrupt
|
|
||||||
@$(MD5SUM) test.hex
|
|
||||||
# test pwm
|
# test pwm
|
||||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
|||||||
@@ -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 62 microcontroller boards are currently supported:
|
The following 57 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)
|
||||||
@@ -53,7 +53,6 @@ The following 62 microcontroller boards are currently supported:
|
|||||||
* [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759)
|
* [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759)
|
||||||
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
|
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
|
||||||
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
|
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
|
||||||
* [Adafruit Grand Central M4](https://www.adafruit.com/product/4064)
|
|
||||||
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
|
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
|
||||||
* [Adafruit ItsyBitsy M4](https://www.adafruit.com/product/3800)
|
* [Adafruit ItsyBitsy M4](https://www.adafruit.com/product/3800)
|
||||||
* [Adafruit ItsyBitsy nRF52840](https://www.adafruit.com/product/4481)
|
* [Adafruit ItsyBitsy nRF52840](https://www.adafruit.com/product/4481)
|
||||||
@@ -64,7 +63,6 @@ The following 62 microcontroller boards are currently supported:
|
|||||||
* [Adafruit PyPortal](https://www.adafruit.com/product/4116)
|
* [Adafruit PyPortal](https://www.adafruit.com/product/4116)
|
||||||
* [Adafruit QT Py](https://www.adafruit.com/product/4600)
|
* [Adafruit QT Py](https://www.adafruit.com/product/4600)
|
||||||
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
|
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
|
||||||
* [Arduino Mega 1280](https://www.arduino.cc/en/Main/arduinoBoardMega/)
|
|
||||||
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
|
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
|
||||||
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
|
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
|
||||||
* [Arduino Nano](https://store.arduino.cc/arduino-nano)
|
* [Arduino Nano](https://store.arduino.cc/arduino-nano)
|
||||||
@@ -86,7 +84,6 @@ The following 62 microcontroller boards are currently supported:
|
|||||||
* [Nordic Semiconductor PCA10031](https://www.nordicsemi.com/eng/Products/nRF51-Dongle)
|
* [Nordic Semiconductor PCA10031](https://www.nordicsemi.com/eng/Products/nRF51-Dongle)
|
||||||
* [Nordic Semiconductor PCA10040](https://www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF52-DK)
|
* [Nordic Semiconductor PCA10040](https://www.nordicsemi.com/eng/Products/Bluetooth-low-energy/nRF52-DK)
|
||||||
* [Nordic Semiconductor PCA10056](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
|
* [Nordic Semiconductor PCA10056](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK)
|
||||||
* [Nordic Semiconductor pca10059](https://www.nordicsemi.com/Software-and-tools/Development-Kits/nRF52840-Dongle)
|
|
||||||
* [Particle Argon](https://docs.particle.io/datasheets/wi-fi/argon-datasheet/)
|
* [Particle Argon](https://docs.particle.io/datasheets/wi-fi/argon-datasheet/)
|
||||||
* [Particle Boron](https://docs.particle.io/datasheets/cellular/boron-datasheet/)
|
* [Particle Boron](https://docs.particle.io/datasheets/cellular/boron-datasheet/)
|
||||||
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
|
* [Particle Xenon](https://docs.particle.io/datasheets/discontinued/xenon-datasheet/)
|
||||||
@@ -101,8 +98,6 @@ The following 62 microcontroller boards are currently supported:
|
|||||||
* [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 "Nucleo" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
|
* [ST Micro "Nucleo" F722ZE](https://www.st.com/en/evaluation-tools/nucleo-f722ze.html)
|
||||||
* [ST Micro "Nucleo" L031K6](https://www.st.com/ja/evaluation-tools/nucleo-l031k6.html)
|
|
||||||
* [ST Micro "Nucleo" L432KC](https://www.st.com/ja/evaluation-tools/nucleo-l432kc.html)
|
|
||||||
* [ST Micro "Nucleo" L552ZE](https://www.st.com/en/evaluation-tools/nucleo-l552ze-q.html)
|
* [ST Micro "Nucleo" L552ZE](https://www.st.com/en/evaluation-tools/nucleo-l552ze-q.html)
|
||||||
* [ST Micro STM32F103XX "Bluepill"](https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill)
|
* [ST Micro STM32F103XX "Bluepill"](https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill)
|
||||||
* [ST Micro STM32F407 "Discovery"](https://www.st.com/en/evaluation-tools/stm32f4discovery.html)
|
* [ST Micro STM32F407 "Discovery"](https://www.st.com/en/evaluation-tools/stm32f4discovery.html)
|
||||||
|
|||||||
+9
-10
@@ -39,11 +39,6 @@ type BuildResult struct {
|
|||||||
// The directory of the main package. This is useful for testing as the test
|
// The directory of the main package. This is useful for testing as the test
|
||||||
// binary must be run in the directory of the tested package.
|
// binary must be run in the directory of the tested package.
|
||||||
MainDir string
|
MainDir string
|
||||||
|
|
||||||
// ImportPath is the import path of the main package. This is useful for
|
|
||||||
// correctly printing test results: the import path isn't always the same as
|
|
||||||
// the path listed on the command line.
|
|
||||||
ImportPath string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// packageAction is the struct that is serialized to JSON and hashed, to work as
|
// packageAction is the struct that is serialized to JSON and hashed, to work as
|
||||||
@@ -99,7 +94,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
DefaultStackSize: config.Target.DefaultStackSize,
|
DefaultStackSize: config.Target.DefaultStackSize,
|
||||||
NeedsStackObjects: config.NeedsStackObjects(),
|
NeedsStackObjects: config.NeedsStackObjects(),
|
||||||
Debug: config.Debug(),
|
Debug: config.Debug(),
|
||||||
LLVMFeatures: config.LLVMFeatures(),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the target machine, which is the LLVM object that contains all
|
// Load the target machine, which is the LLVM object that contains all
|
||||||
@@ -306,7 +300,13 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return os.Rename(f.Name(), bitcodePath)
|
|
||||||
|
// Rename may fail if another process is trying to write to
|
||||||
|
// the same file. However, in this case, the failure is
|
||||||
|
// acceptable because the result of the other process can be
|
||||||
|
// used.
|
||||||
|
os.Rename(f.Name(), bitcodePath)
|
||||||
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
jobs = append(jobs, job)
|
jobs = append(jobs, job)
|
||||||
@@ -643,9 +643,8 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
return fmt.Errorf("unknown output binary format: %s", outputBinaryFormat)
|
return fmt.Errorf("unknown output binary format: %s", outputBinaryFormat)
|
||||||
}
|
}
|
||||||
return action(BuildResult{
|
return action(BuildResult{
|
||||||
Binary: tmppath,
|
Binary: tmppath,
|
||||||
MainDir: lprogram.MainPkg().Dir,
|
MainDir: lprogram.MainPkg().Dir,
|
||||||
ImportPath: lprogram.MainPkg().ImportPath,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,18 +17,10 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if options.OpenOCDCommands != nil {
|
|
||||||
// Override the OpenOCDCommands from the target spec if specified on
|
|
||||||
// the command-line
|
|
||||||
spec.OpenOCDCommands = options.OpenOCDCommands
|
|
||||||
}
|
|
||||||
|
|
||||||
goroot := goenv.Get("GOROOT")
|
goroot := goenv.Get("GOROOT")
|
||||||
if goroot == "" {
|
if goroot == "" {
|
||||||
return nil, errors.New("cannot locate $GOROOT, please set it manually")
|
return nil, errors.New("cannot locate $GOROOT, please set it manually")
|
||||||
}
|
}
|
||||||
|
|
||||||
major, minor, err := goenv.GetGorootVersion(goroot)
|
major, minor, err := goenv.GetGorootVersion(goroot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
|
return nil, fmt.Errorf("could not read version from GOROOT (%v): %v", goroot, err)
|
||||||
@@ -36,9 +28,7 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
|
|||||||
if major != 1 || minor < 13 || minor > 16 {
|
if major != 1 || minor < 13 || minor > 16 {
|
||||||
return nil, fmt.Errorf("requires go version 1.13 through 1.16, got go%d.%d", major, minor)
|
return nil, fmt.Errorf("requires go version 1.13 through 1.16, got go%d.%d", major, minor)
|
||||||
}
|
}
|
||||||
|
|
||||||
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
clangHeaderPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
|
||||||
|
|
||||||
return &compileopts.Config{
|
return &compileopts.Config{
|
||||||
Options: options,
|
Options: options,
|
||||||
Target: spec,
|
Target: spec,
|
||||||
|
|||||||
@@ -80,7 +80,12 @@ func (c *Config) GC() string {
|
|||||||
if c.Target.GC != "" {
|
if c.Target.GC != "" {
|
||||||
return c.Target.GC
|
return c.Target.GC
|
||||||
}
|
}
|
||||||
return "conservative"
|
for _, tag := range c.Target.BuildTags {
|
||||||
|
if tag == "baremetal" || tag == "wasm" {
|
||||||
|
return "conservative"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "extalloc"
|
||||||
}
|
}
|
||||||
|
|
||||||
// NeedsStackObjects returns true if the compiler should insert stack objects
|
// NeedsStackObjects returns true if the compiler should insert stack objects
|
||||||
@@ -337,10 +342,6 @@ func (c *Config) WasmAbi() string {
|
|||||||
return c.Target.WasmAbi
|
return c.Target.WasmAbi
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) LLVMFeatures() string {
|
|
||||||
return c.Options.LLVMFeatures
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
+18
-20
@@ -17,26 +17,24 @@ var (
|
|||||||
// 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 {
|
||||||
Target string
|
Target string
|
||||||
Opt string
|
Opt string
|
||||||
GC string
|
GC string
|
||||||
PanicStrategy string
|
PanicStrategy string
|
||||||
Scheduler string
|
Scheduler string
|
||||||
PrintIR bool
|
PrintIR bool
|
||||||
DumpSSA bool
|
DumpSSA bool
|
||||||
VerifyIR bool
|
VerifyIR bool
|
||||||
PrintCommands bool
|
PrintCommands bool
|
||||||
Debug bool
|
Debug bool
|
||||||
PrintSizes string
|
PrintSizes string
|
||||||
PrintAllocs *regexp.Regexp // regexp string
|
PrintAllocs *regexp.Regexp // regexp string
|
||||||
PrintStacks bool
|
PrintStacks bool
|
||||||
Tags string
|
Tags string
|
||||||
WasmAbi string
|
WasmAbi string
|
||||||
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
|
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
|
||||||
TestConfig TestConfig
|
TestConfig TestConfig
|
||||||
Programmer string
|
Programmer string
|
||||||
OpenOCDCommands []string
|
|
||||||
LLVMFeatures string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify performs a validation on the given options, raising an error if options are not valid.
|
// Verify performs a validation on the given options, raising an error if options are not valid.
|
||||||
|
|||||||
+8
-12
@@ -239,26 +239,22 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
|||||||
// No target spec available. Use the default one, useful on most systems
|
// No target spec available. Use the default one, useful on most systems
|
||||||
// with a regular OS.
|
// with a regular OS.
|
||||||
spec := TargetSpec{
|
spec := TargetSpec{
|
||||||
Triple: triple,
|
Triple: triple,
|
||||||
GOOS: goos,
|
GOOS: goos,
|
||||||
GOARCH: goarch,
|
GOARCH: goarch,
|
||||||
BuildTags: []string{goos, goarch},
|
BuildTags: []string{goos, goarch},
|
||||||
Scheduler: "tasks",
|
Linker: "cc",
|
||||||
Linker: "cc",
|
CFlags: []string{"--target=" + triple},
|
||||||
DefaultStackSize: 1024 * 64, // 64kB
|
GDB: []string{"gdb"},
|
||||||
CFlags: []string{"--target=" + triple},
|
PortReset: "false",
|
||||||
GDB: []string{"gdb"},
|
|
||||||
PortReset: "false",
|
|
||||||
}
|
}
|
||||||
if goos == "darwin" {
|
if goos == "darwin" {
|
||||||
spec.CFlags = append(spec.CFlags, "-isysroot", "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk")
|
|
||||||
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
|
spec.LDFlags = append(spec.LDFlags, "-Wl,-dead_strip")
|
||||||
} else {
|
} else {
|
||||||
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
|
spec.LDFlags = append(spec.LDFlags, "-no-pie", "-Wl,--gc-sections") // WARNING: clang < 5.0 requires -nopie
|
||||||
}
|
}
|
||||||
if goarch != "wasm" {
|
if goarch != "wasm" {
|
||||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/gc_"+goarch+".S")
|
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/gc_"+goarch+".S")
|
||||||
spec.ExtraFiles = append(spec.ExtraFiles, "src/internal/task/task_stack_"+goarch+".S")
|
|
||||||
}
|
}
|
||||||
if goarch != runtime.GOARCH {
|
if goarch != runtime.GOARCH {
|
||||||
// Some educated guesses as to how to invoke helper programs.
|
// Some educated guesses as to how to invoke helper programs.
|
||||||
|
|||||||
+2
-56
@@ -59,7 +59,6 @@ type Config struct {
|
|||||||
DefaultStackSize uint64
|
DefaultStackSize uint64
|
||||||
NeedsStackObjects bool
|
NeedsStackObjects bool
|
||||||
Debug bool // Whether to emit debug information in the LLVM module.
|
Debug bool // Whether to emit debug information in the LLVM module.
|
||||||
LLVMFeatures string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// compilerContext contains function-independent data that should still be
|
// compilerContext contains function-independent data that should still be
|
||||||
@@ -186,12 +185,7 @@ func NewTargetMachine(config *Config) (llvm.TargetMachine, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.TargetMachine{}, err
|
return llvm.TargetMachine{}, err
|
||||||
}
|
}
|
||||||
|
features := strings.Join(config.Features, ",")
|
||||||
feat := config.Features
|
|
||||||
if len(config.LLVMFeatures) > 0 {
|
|
||||||
feat = append(feat, config.LLVMFeatures)
|
|
||||||
}
|
|
||||||
features := strings.Join(feat, ",")
|
|
||||||
|
|
||||||
var codeModel llvm.CodeModel
|
var codeModel llvm.CodeModel
|
||||||
var relocationModel llvm.RelocMode
|
var relocationModel llvm.RelocMode
|
||||||
@@ -970,59 +964,11 @@ func (b *builder) createFunction() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// posser is an interface that's implemented by both ssa.Value and
|
|
||||||
// ssa.Instruction. It is implemented by everything that has a Pos() method,
|
|
||||||
// which is all that getPos() needs.
|
|
||||||
type posser interface {
|
|
||||||
Pos() token.Pos
|
|
||||||
}
|
|
||||||
|
|
||||||
// getPos returns position information for a ssa.Value or ssa.Instruction.
|
|
||||||
//
|
|
||||||
// Not all instructions have position information, especially when they're
|
|
||||||
// implicit (such as implicit casts or implicit returns at the end of a
|
|
||||||
// function). In these cases, it makes sense to try a bit harder to guess what
|
|
||||||
// the position really should be.
|
|
||||||
func getPos(val posser) token.Pos {
|
|
||||||
pos := val.Pos()
|
|
||||||
if pos != token.NoPos {
|
|
||||||
// Easy: position is known.
|
|
||||||
return pos
|
|
||||||
}
|
|
||||||
|
|
||||||
// No position information is known.
|
|
||||||
switch val := val.(type) {
|
|
||||||
case *ssa.MakeInterface:
|
|
||||||
return getPos(val.X)
|
|
||||||
case *ssa.Return:
|
|
||||||
syntax := val.Parent().Syntax()
|
|
||||||
if syntax != nil {
|
|
||||||
// non-synthetic
|
|
||||||
return syntax.End()
|
|
||||||
}
|
|
||||||
return token.NoPos
|
|
||||||
case *ssa.FieldAddr:
|
|
||||||
return getPos(val.X)
|
|
||||||
case *ssa.IndexAddr:
|
|
||||||
return getPos(val.X)
|
|
||||||
case *ssa.Slice:
|
|
||||||
return getPos(val.X)
|
|
||||||
case *ssa.Store:
|
|
||||||
return getPos(val.Addr)
|
|
||||||
case *ssa.Extract:
|
|
||||||
return getPos(val.Tuple)
|
|
||||||
default:
|
|
||||||
// This is reachable, for example with *ssa.Const, *ssa.If, and
|
|
||||||
// *ssa.Jump. They might be implemented in some way in the future.
|
|
||||||
return token.NoPos
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// createInstruction builds the LLVM IR equivalent instructions for the
|
// createInstruction builds the LLVM IR equivalent instructions for the
|
||||||
// particular Go SSA instruction.
|
// particular Go SSA instruction.
|
||||||
func (b *builder) createInstruction(instr ssa.Instruction) {
|
func (b *builder) createInstruction(instr ssa.Instruction) {
|
||||||
if b.Debug {
|
if b.Debug {
|
||||||
pos := b.program.Fset.Position(getPos(instr))
|
pos := b.program.Fset.Position(instr.Pos())
|
||||||
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
|
b.SetCurrentDebugLocation(uint(pos.Line), uint(pos.Column), b.difunc, llvm.Metadata{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ func TestCompiler(t *testing.T) {
|
|||||||
t.Skip("compiler tests require LLVM 11 or above, got LLVM ", llvm.Version)
|
t.Skip("compiler tests require LLVM 11 or above, got LLVM ", llvm.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
target, err := compileopts.LoadTarget("wasm")
|
target, err := compileopts.LoadTarget("i686--linux")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("failed to load target:", err)
|
t.Fatal("failed to load target:", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,9 +34,6 @@ func (b *builder) createGoInstruction(funcPtr llvm.Value, params []llvm.Value, p
|
|||||||
} else {
|
} else {
|
||||||
// The stack size is fixed at compile time. By emitting it here as a
|
// The stack size is fixed at compile time. By emitting it here as a
|
||||||
// constant, it can be optimized.
|
// constant, it can be optimized.
|
||||||
if b.Scheduler == "tasks" && b.DefaultStackSize == 0 {
|
|
||||||
b.addError(pos, "default stack size for goroutines is not set")
|
|
||||||
}
|
|
||||||
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
|
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
|
||||||
}
|
}
|
||||||
case "coroutines":
|
case "coroutines":
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
; ModuleID = 'basic.go'
|
; ModuleID = 'basic.go'
|
||||||
source_filename = "basic.go"
|
source_filename = "basic.go"
|
||||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
|
||||||
target triple = "wasm32--wasi"
|
target triple = "i686--linux"
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
; ModuleID = 'float.go'
|
; ModuleID = 'float.go'
|
||||||
source_filename = "float.go"
|
source_filename = "float.go"
|
||||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
|
||||||
target triple = "wasm32--wasi"
|
target triple = "i686--linux"
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
; ModuleID = 'func.go'
|
; ModuleID = 'func.go'
|
||||||
source_filename = "func.go"
|
source_filename = "func.go"
|
||||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
|
||||||
target triple = "wasm32--wasi"
|
target triple = "i686--linux"
|
||||||
|
|
||||||
%runtime.funcValueWithSignature = type { i32, i8* }
|
%runtime.funcValueWithSignature = type { i32, i8* }
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
; ModuleID = 'interface.go'
|
; ModuleID = 'interface.go'
|
||||||
source_filename = "interface.go"
|
source_filename = "interface.go"
|
||||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
|
||||||
target triple = "wasm32--wasi"
|
target triple = "i686--linux"
|
||||||
|
|
||||||
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID* }
|
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID* }
|
||||||
%runtime.interfaceMethodInfo = type { i8*, i32 }
|
%runtime.interfaceMethodInfo = type { i8*, i32 }
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
; ModuleID = 'pointer.go'
|
; ModuleID = 'pointer.go'
|
||||||
source_filename = "pointer.go"
|
source_filename = "pointer.go"
|
||||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
|
||||||
target triple = "wasm32--wasi"
|
target triple = "i686--linux"
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
; ModuleID = 'slice.go'
|
; ModuleID = 'slice.go'
|
||||||
source_filename = "slice.go"
|
source_filename = "slice.go"
|
||||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
|
||||||
target triple = "wasm32--wasi"
|
target triple = "i686--linux"
|
||||||
|
|
||||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
; ModuleID = 'string.go'
|
; ModuleID = 'string.go'
|
||||||
source_filename = "string.go"
|
source_filename = "string.go"
|
||||||
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
|
||||||
target triple = "wasm32--wasi"
|
target triple = "i686--linux"
|
||||||
|
|
||||||
%runtime._string = type { i8*, i32 }
|
%runtime._string = type { i8*, i32 }
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
// Version of TinyGo.
|
// Version of TinyGo.
|
||||||
// Update this value before release of new version of software.
|
// Update this value before release of new version of software.
|
||||||
const Version = "0.18.0"
|
const Version = "0.18.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.
|
||||||
|
|||||||
+6
-22
@@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -931,31 +930,16 @@ func (r *runner) runAtRuntime(fn *function, inst instruction, locals []value, me
|
|||||||
result = r.builder.CreateBitCast(operands[0], inst.llvmInst.Type(), inst.name)
|
result = r.builder.CreateBitCast(operands[0], inst.llvmInst.Type(), inst.name)
|
||||||
case llvm.ExtractValue:
|
case llvm.ExtractValue:
|
||||||
indices := inst.llvmInst.Indices()
|
indices := inst.llvmInst.Indices()
|
||||||
// Note: the Go LLVM API doesn't support multiple indices, so simulate
|
if len(indices) != 1 {
|
||||||
// this operation with some extra extractvalue instructions. Hopefully
|
panic("expected exactly one index")
|
||||||
// this is optimized to a single instruction.
|
|
||||||
agg := operands[0]
|
|
||||||
for i := 0; i < len(indices)-1; i++ {
|
|
||||||
agg = r.builder.CreateExtractValue(agg, int(indices[i]), inst.name+".agg")
|
|
||||||
}
|
}
|
||||||
result = r.builder.CreateExtractValue(agg, int(indices[len(indices)-1]), inst.name)
|
result = r.builder.CreateExtractValue(operands[0], int(indices[0]), inst.name)
|
||||||
case llvm.InsertValue:
|
case llvm.InsertValue:
|
||||||
indices := inst.llvmInst.Indices()
|
indices := inst.llvmInst.Indices()
|
||||||
// Similar to extractvalue, we're working around a limitation in the Go
|
if len(indices) != 1 {
|
||||||
// LLVM API here by splitting the insertvalue into multiple instructions
|
panic("expected exactly one index")
|
||||||
// if there is more than one operand.
|
|
||||||
agg := operands[0]
|
|
||||||
aggregates := []llvm.Value{agg}
|
|
||||||
for i := 0; i < len(indices)-1; i++ {
|
|
||||||
agg = r.builder.CreateExtractValue(agg, int(indices[i]), inst.name+".agg"+strconv.Itoa(i))
|
|
||||||
aggregates = append(aggregates, agg)
|
|
||||||
}
|
}
|
||||||
result = operands[1]
|
result = r.builder.CreateInsertValue(operands[0], operands[1], int(indices[0]), inst.name)
|
||||||
for i := len(indices) - 1; i >= 0; i-- {
|
|
||||||
agg := aggregates[i]
|
|
||||||
result = r.builder.CreateInsertValue(agg, result, int(indices[i]), inst.name+".insertvalue"+strconv.Itoa(i))
|
|
||||||
}
|
|
||||||
|
|
||||||
case llvm.Add:
|
case llvm.Add:
|
||||||
result = r.builder.CreateAdd(operands[0], operands[1], inst.name)
|
result = r.builder.CreateAdd(operands[0], operands[1], inst.name)
|
||||||
case llvm.Sub:
|
case llvm.Sub:
|
||||||
|
|||||||
Vendored
-10
@@ -8,7 +8,6 @@ target triple = "x86_64--linux"
|
|||||||
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
||||||
@main.exposedValue1 = global i16 0
|
@main.exposedValue1 = global i16 0
|
||||||
@main.exposedValue2 = global i16 0
|
@main.exposedValue2 = global i16 0
|
||||||
@main.insertedValue = global {i8, i32, {float, {i64, i16}}} zeroinitializer
|
|
||||||
|
|
||||||
declare void @runtime.printint64(i64) unnamed_addr
|
declare void @runtime.printint64(i64) unnamed_addr
|
||||||
|
|
||||||
@@ -72,13 +71,6 @@ entry:
|
|||||||
call void @runtime.printint64(i64 %switch1)
|
call void @runtime.printint64(i64 %switch1)
|
||||||
call void @runtime.printint64(i64 %switch2)
|
call void @runtime.printint64(i64 %switch2)
|
||||||
|
|
||||||
; Test extractvalue/insertvalue with multiple operands.
|
|
||||||
%agg = call {i8, i32, {float, {i64, i16}}} @nestedStruct()
|
|
||||||
%elt = extractvalue {i8, i32, {float, {i64, i16}}} %agg, 2, 1, 0
|
|
||||||
call void @runtime.printint64(i64 %elt)
|
|
||||||
%agg2 = insertvalue {i8, i32, {float, {i64, i16}}} %agg, i64 5, 2, 1, 0
|
|
||||||
store {i8, i32, {float, {i64, i16}}} %agg2, {i8, i32, {float, {i64, i16}}}* @main.insertedValue
|
|
||||||
|
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,5 +112,3 @@ two:
|
|||||||
otherwise:
|
otherwise:
|
||||||
ret i64 -1
|
ret i64 -1
|
||||||
}
|
}
|
||||||
|
|
||||||
declare {i8, i32, {float, {i64, i16}}} @nestedStruct()
|
|
||||||
|
|||||||
Vendored
-14
@@ -7,7 +7,6 @@ target triple = "x86_64--linux"
|
|||||||
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
@main.exportedValue = global [1 x i16*] [i16* @main.exposedValue1]
|
||||||
@main.exposedValue1 = global i16 0
|
@main.exposedValue1 = global i16 0
|
||||||
@main.exposedValue2 = local_unnamed_addr global i16 0
|
@main.exposedValue2 = local_unnamed_addr global i16 0
|
||||||
@main.insertedValue = local_unnamed_addr global { i8, i32, { float, { i64, i16 } } } zeroinitializer
|
|
||||||
|
|
||||||
declare void @runtime.printint64(i64) unnamed_addr
|
declare void @runtime.printint64(i64) unnamed_addr
|
||||||
|
|
||||||
@@ -28,17 +27,6 @@ entry:
|
|||||||
store i16 7, i16* @main.exposedValue2
|
store i16 7, i16* @main.exposedValue2
|
||||||
call void @runtime.printint64(i64 6)
|
call void @runtime.printint64(i64 6)
|
||||||
call void @runtime.printint64(i64 -1)
|
call void @runtime.printint64(i64 -1)
|
||||||
%agg = call { i8, i32, { float, { i64, i16 } } } @nestedStruct()
|
|
||||||
%elt.agg = extractvalue { i8, i32, { float, { i64, i16 } } } %agg, 2
|
|
||||||
%elt.agg1 = extractvalue { float, { i64, i16 } } %elt.agg, 1
|
|
||||||
%elt = extractvalue { i64, i16 } %elt.agg1, 0
|
|
||||||
call void @runtime.printint64(i64 %elt)
|
|
||||||
%agg2.agg0 = extractvalue { i8, i32, { float, { i64, i16 } } } %agg, 2
|
|
||||||
%agg2.agg1 = extractvalue { float, { i64, i16 } } %agg2.agg0, 1
|
|
||||||
%agg2.insertvalue2 = insertvalue { i64, i16 } %agg2.agg1, i64 5, 0
|
|
||||||
%agg2.insertvalue1 = insertvalue { float, { i64, i16 } } %agg2.agg0, { i64, i16 } %agg2.insertvalue2, 1
|
|
||||||
%agg2.insertvalue0 = insertvalue { i8, i32, { float, { i64, i16 } } } %agg, { float, { i64, i16 } } %agg2.insertvalue1, 2
|
|
||||||
store { i8, i32, { float, { i64, i16 } } } %agg2.insertvalue0, { i8, i32, { float, { i64, i16 } } }* @main.insertedValue
|
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,5 +67,3 @@ two: ; preds = %entry
|
|||||||
otherwise: ; preds = %entry
|
otherwise: ; preds = %entry
|
||||||
ret i64 -1
|
ret i64 -1
|
||||||
}
|
}
|
||||||
|
|
||||||
declare { i8, i32, { float, { i64, i16 } } } @nestedStruct() local_unnamed_addr
|
|
||||||
|
|||||||
@@ -23,13 +23,3 @@ type Error struct {
|
|||||||
func (e Error) Error() string {
|
func (e Error) Error() string {
|
||||||
return e.Err.Error()
|
return e.Err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error returned when loading a *Program for a test binary but no test files
|
|
||||||
// are present.
|
|
||||||
type NoTestFilesError struct {
|
|
||||||
ImportPath string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e NoTestFilesError) Error() string {
|
|
||||||
return "no test files"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -210,12 +210,6 @@ func Load(config *compileopts.Config, inputPkgs []string, clangHeaders string, t
|
|||||||
p.Packages[pkg.ImportPath] = pkg
|
p.Packages[pkg.ImportPath] = pkg
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.TestConfig.CompileTestBinary && !strings.HasSuffix(p.sorted[len(p.sorted)-1].ImportPath, ".test") {
|
|
||||||
// Trying to compile a test binary but there are no test files in this
|
|
||||||
// package.
|
|
||||||
return p, NoTestFilesError{p.sorted[len(p.sorted)-1].ImportPath}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p, nil
|
return p, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -136,17 +136,15 @@ func Build(pkgName, outpath string, options *compileopts.Options) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test runs the tests in the given package. Returns whether the test passed and
|
// Test runs the tests in the given package.
|
||||||
// possibly an error if the test failed to run.
|
func Test(pkgName string, options *compileopts.Options, testCompileOnly bool, outpath string) error {
|
||||||
func Test(pkgName string, options *compileopts.Options, testCompileOnly bool, outpath string) (bool, error) {
|
|
||||||
options.TestConfig.CompileTestBinary = true
|
options.TestConfig.CompileTestBinary = true
|
||||||
config, err := builder.NewConfig(options)
|
config, err := builder.NewConfig(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var passed bool
|
return builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error {
|
||||||
err = builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error {
|
|
||||||
if testCompileOnly || outpath != "" {
|
if testCompileOnly || outpath != "" {
|
||||||
// Write test binary to the specified file name.
|
// Write test binary to the specified file name.
|
||||||
if outpath == "" {
|
if outpath == "" {
|
||||||
@@ -160,78 +158,48 @@ func Test(pkgName string, options *compileopts.Options, testCompileOnly bool, ou
|
|||||||
// Do not run the test.
|
// Do not run the test.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
if len(config.Target.Emulator) == 0 {
|
||||||
// Run the test.
|
// Run directly.
|
||||||
start := time.Now()
|
cmd := executeCommand(config.Options, result.Binary)
|
||||||
var err error
|
cmd.Stdout = os.Stdout
|
||||||
passed, err = runPackageTest(config, result)
|
cmd.Stderr = os.Stderr
|
||||||
if err != nil {
|
cmd.Dir = result.MainDir
|
||||||
return err
|
err := cmd.Run()
|
||||||
}
|
if err != nil {
|
||||||
duration := time.Since(start)
|
// Propagate the exit code
|
||||||
|
if err, ok := err.(*exec.ExitError); ok {
|
||||||
// Print the result.
|
os.Exit(err.ExitCode())
|
||||||
importPath := strings.TrimSuffix(result.ImportPath, ".test")
|
}
|
||||||
if passed {
|
return &commandError{"failed to run compiled binary", result.Binary, err}
|
||||||
fmt.Printf("ok \t%s\t%.3fs\n", importPath, duration.Seconds())
|
}
|
||||||
|
return nil
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("FAIL\t%s\t%.3fs\n", importPath, duration.Seconds())
|
// Run in an emulator.
|
||||||
|
args := append(config.Target.Emulator[1:], result.Binary)
|
||||||
|
cmd := executeCommand(config.Options, config.Target.Emulator[0], args...)
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
w := io.MultiWriter(os.Stdout, buf)
|
||||||
|
cmd.Stdout = w
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
if err, ok := err.(*exec.ExitError); !ok || !err.Exited() {
|
||||||
|
// Workaround for QEMU which always exits with an error.
|
||||||
|
return &commandError{"failed to run emulator with", result.Binary, err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
testOutput := string(buf.Bytes())
|
||||||
|
if testOutput == "PASS\n" || strings.HasSuffix(testOutput, "\nPASS\n") {
|
||||||
|
// Test passed.
|
||||||
|
return nil
|
||||||
|
} else {
|
||||||
|
// Test failed, either by ending with the word "FAIL" or with a
|
||||||
|
// panic of some sort.
|
||||||
|
os.Exit(1)
|
||||||
|
return nil // unreachable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
})
|
})
|
||||||
if err, ok := err.(loader.NoTestFilesError); ok {
|
|
||||||
fmt.Printf("? \t%s\t[no test files]\n", err.ImportPath)
|
|
||||||
// Pretend the test passed - it at least didn't fail.
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
return passed, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// runPackageTest runs a test binary that was previously built. The return
|
|
||||||
// values are whether the test passed and any errors encountered while trying to
|
|
||||||
// run the binary.
|
|
||||||
func runPackageTest(config *compileopts.Config, result builder.BuildResult) (bool, error) {
|
|
||||||
if len(config.Target.Emulator) == 0 {
|
|
||||||
// Run directly.
|
|
||||||
cmd := executeCommand(config.Options, result.Binary)
|
|
||||||
cmd.Stdout = os.Stdout
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
cmd.Dir = result.MainDir
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
if _, ok := err.(*exec.ExitError); ok {
|
|
||||||
// Binary exited with a non-zero exit code, which means the test
|
|
||||||
// failed.
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return false, &commandError{"failed to run compiled binary", result.Binary, err}
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
} else {
|
|
||||||
// Run in an emulator.
|
|
||||||
args := append(config.Target.Emulator[1:], result.Binary)
|
|
||||||
cmd := executeCommand(config.Options, config.Target.Emulator[0], args...)
|
|
||||||
buf := &bytes.Buffer{}
|
|
||||||
w := io.MultiWriter(os.Stdout, buf)
|
|
||||||
cmd.Stdout = w
|
|
||||||
cmd.Stderr = os.Stderr
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
if err, ok := err.(*exec.ExitError); !ok || !err.Exited() {
|
|
||||||
// Workaround for QEMU which always exits with an error.
|
|
||||||
return false, &commandError{"failed to run emulator with", result.Binary, err}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
testOutput := string(buf.Bytes())
|
|
||||||
if testOutput == "PASS\n" || strings.HasSuffix(testOutput, "\nPASS\n") {
|
|
||||||
// Test passed.
|
|
||||||
return true, nil
|
|
||||||
} else {
|
|
||||||
// Test failed, either by ending with the word "FAIL" or with a
|
|
||||||
// panic of some sort.
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flash builds and flashes the built binary to the given serial port.
|
// Flash builds and flashes the built binary to the given serial port.
|
||||||
@@ -714,9 +682,7 @@ func getDefaultPort(portCandidates []string) (port string, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range portsList {
|
for _, p := range portsList {
|
||||||
if p.IsUSB {
|
ports = append(ports, p.Name)
|
||||||
ports = append(ports, p.Name)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ports == nil || len(ports) == 0 {
|
if ports == nil || len(ports) == 0 {
|
||||||
@@ -939,13 +905,11 @@ func main() {
|
|||||||
printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
|
printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
|
||||||
printCommands := flag.Bool("x", false, "Print commands")
|
printCommands := flag.Bool("x", false, "Print commands")
|
||||||
nodebug := flag.Bool("no-debug", false, "disable DWARF debug symbol generation")
|
nodebug := flag.Bool("no-debug", false, "disable DWARF debug symbol generation")
|
||||||
ocdCommandsString := flag.String("ocd-commands", "", "OpenOCD commands, overriding target spec (can specify multiple separated by commas)")
|
|
||||||
ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug")
|
ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug")
|
||||||
port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)")
|
port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)")
|
||||||
programmer := flag.String("programmer", "", "which hardware programmer to use")
|
programmer := flag.String("programmer", "", "which hardware programmer to use")
|
||||||
ldflags := flag.String("ldflags", "", "Go link tool compatible ldflags")
|
ldflags := flag.String("ldflags", "", "Go link tool compatible ldflags")
|
||||||
wasmAbi := flag.String("wasm-abi", "", "WebAssembly ABI conventions: js (no i64 params) or generic")
|
wasmAbi := flag.String("wasm-abi", "", "WebAssembly ABI conventions: js (no i64 params) or generic")
|
||||||
llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable")
|
|
||||||
|
|
||||||
var flagJSON, flagDeps *bool
|
var flagJSON, flagDeps *bool
|
||||||
if command == "help" || command == "list" {
|
if command == "help" || command == "list" {
|
||||||
@@ -979,7 +943,6 @@ func main() {
|
|||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
var printAllocs *regexp.Regexp
|
var printAllocs *regexp.Regexp
|
||||||
if *printAllocsString != "" {
|
if *printAllocsString != "" {
|
||||||
printAllocs, err = regexp.Compile(*printAllocsString)
|
printAllocs, err = regexp.Compile(*printAllocsString)
|
||||||
@@ -988,32 +951,24 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var ocdCommands []string
|
|
||||||
if *ocdCommandsString != "" {
|
|
||||||
ocdCommands = strings.Split(*ocdCommandsString, ",")
|
|
||||||
}
|
|
||||||
|
|
||||||
options := &compileopts.Options{
|
options := &compileopts.Options{
|
||||||
Target: *target,
|
Target: *target,
|
||||||
Opt: *opt,
|
Opt: *opt,
|
||||||
GC: *gc,
|
GC: *gc,
|
||||||
PanicStrategy: *panicStrategy,
|
PanicStrategy: *panicStrategy,
|
||||||
Scheduler: *scheduler,
|
Scheduler: *scheduler,
|
||||||
PrintIR: *printIR,
|
PrintIR: *printIR,
|
||||||
DumpSSA: *dumpSSA,
|
DumpSSA: *dumpSSA,
|
||||||
VerifyIR: *verifyIR,
|
VerifyIR: *verifyIR,
|
||||||
Debug: !*nodebug,
|
Debug: !*nodebug,
|
||||||
PrintSizes: *printSize,
|
PrintSizes: *printSize,
|
||||||
PrintStacks: *printStacks,
|
PrintStacks: *printStacks,
|
||||||
PrintAllocs: printAllocs,
|
PrintAllocs: printAllocs,
|
||||||
PrintCommands: *printCommands,
|
PrintCommands: *printCommands,
|
||||||
Tags: *tags,
|
Tags: *tags,
|
||||||
GlobalValues: globalVarValues,
|
GlobalValues: globalVarValues,
|
||||||
WasmAbi: *wasmAbi,
|
WasmAbi: *wasmAbi,
|
||||||
Programmer: *programmer,
|
Programmer: *programmer,
|
||||||
OpenOCDCommands: ocdCommands,
|
|
||||||
LLVMFeatures: *llvmFeatures,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Setenv("CC", "clang -target="+*target)
|
os.Setenv("CC", "clang -target="+*target)
|
||||||
@@ -1106,26 +1061,16 @@ func main() {
|
|||||||
err := Run(pkgName, options)
|
err := Run(pkgName, options)
|
||||||
handleCompilerError(err)
|
handleCompilerError(err)
|
||||||
case "test":
|
case "test":
|
||||||
var pkgNames []string
|
pkgName := "."
|
||||||
for i := 0; i < flag.NArg(); i++ {
|
if flag.NArg() == 1 {
|
||||||
pkgNames = append(pkgNames, filepath.ToSlash(flag.Arg(i)))
|
pkgName = filepath.ToSlash(flag.Arg(0))
|
||||||
}
|
} else if flag.NArg() > 1 {
|
||||||
if len(pkgNames) == 0 {
|
fmt.Fprintln(os.Stderr, "test only accepts a single positional argument: package name, but multiple were specified")
|
||||||
pkgNames = []string{"."}
|
usage()
|
||||||
}
|
|
||||||
allTestsPassed := true
|
|
||||||
for _, pkgName := range pkgNames {
|
|
||||||
// TODO: parallelize building the test binaries
|
|
||||||
passed, err := Test(pkgName, options, *testCompileOnlyFlag, outpath)
|
|
||||||
handleCompilerError(err)
|
|
||||||
if !passed {
|
|
||||||
allTestsPassed = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if !allTestsPassed {
|
|
||||||
fmt.Println("FAIL")
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
err := Test(pkgName, options, *testCompileOnlyFlag, outpath)
|
||||||
|
handleCompilerError(err)
|
||||||
case "targets":
|
case "targets":
|
||||||
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
|
dir := filepath.Join(goenv.Get("TINYGOROOT"), "targets")
|
||||||
entries, err := ioutil.ReadDir(dir)
|
entries, err := ioutil.ReadDir(dir)
|
||||||
|
|||||||
+6
-15
@@ -26,21 +26,12 @@ type SCB_Type struct {
|
|||||||
SHPR2 volatile.Register32 // 0xD1C: System Handler Priority Register 2
|
SHPR2 volatile.Register32 // 0xD1C: System Handler Priority Register 2
|
||||||
SHPR3 volatile.Register32 // 0xD20: System Handler Priority Register 3
|
SHPR3 volatile.Register32 // 0xD20: System Handler Priority Register 3
|
||||||
// the following are only applicable for Cortex-M3/M33/M4/M7
|
// the following are only applicable for Cortex-M3/M33/M4/M7
|
||||||
SHCSR volatile.Register32 // 0xD24: System Handler Control and State Register
|
SHCSR volatile.Register32 // 0xD24: System Handler Control and State Register
|
||||||
CFSR volatile.Register32 // 0xD28: Configurable Fault Status Register
|
CFSR volatile.Register32 // 0xD28: Configurable Fault Status Register
|
||||||
HFSR volatile.Register32 // 0xD2C: HardFault Status Register
|
HFSR volatile.Register32 // 0xD2C: HardFault Status Register
|
||||||
DFSR volatile.Register32 // 0xD30: Debug Fault Status Register
|
DFSR volatile.Register32 // 0xD30: Debug Fault Status Register
|
||||||
MMFAR volatile.Register32 // 0xD34: MemManage Fault Address Register
|
MMFAR volatile.Register32 // 0xD34: MemManage Fault Address Register
|
||||||
BFAR volatile.Register32 // 0xD38: BusFault Address Register
|
BFAR volatile.Register32 // 0xD38: BusFault Address Register
|
||||||
AFSR volatile.Register32 // 0xD3C: Auxiliary Fault Status Register
|
|
||||||
PFR [2]volatile.Register32 // 0xD40: Processor Feature Register
|
|
||||||
DFR volatile.Register32 // 0xD48: Debug Feature Register
|
|
||||||
ADR volatile.Register32 // 0xD4C: Auxiliary Feature Register
|
|
||||||
MMFR [4]volatile.Register32 // 0xD50: Memory Model Feature Register
|
|
||||||
ISAR [5]volatile.Register32 // 0xD60: Instruction Set Attributes Register
|
|
||||||
_ [5]uint32 // reserved
|
|
||||||
CPACR volatile.Register32 // 0xD88: Coprocessor Access Control Register
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var SCB = (*SCB_Type)(unsafe.Pointer(uintptr(SCB_BASE)))
|
var SCB = (*SCB_Type)(unsafe.Pointer(uintptr(SCB_BASE)))
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
// +build feather_m4_can
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// power on the CAN Transceiver
|
|
||||||
// https://learn.adafruit.com/adafruit-feather-m4-can-express/pinouts#can-bus-3078990-8
|
|
||||||
boost_en := machine.BOOST_EN
|
|
||||||
boost_en.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
|
||||||
boost_en.High()
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
can1 := machine.CAN1
|
|
||||||
can1.Configure(machine.CANConfig{
|
|
||||||
TransferRate: machine.CANTransferRate500kbps,
|
|
||||||
TransferRateFD: machine.CANTransferRate1000kbps,
|
|
||||||
Rx: machine.CAN1_RX,
|
|
||||||
Tx: machine.CAN1_TX,
|
|
||||||
Standby: machine.CAN1_STANDBY,
|
|
||||||
})
|
|
||||||
|
|
||||||
can0 := machine.CAN0
|
|
||||||
can0.Configure(machine.CANConfig{
|
|
||||||
TransferRate: machine.CANTransferRate500kbps,
|
|
||||||
TransferRateFD: machine.CANTransferRate1000kbps,
|
|
||||||
Rx: machine.CAN0_RX,
|
|
||||||
Tx: machine.CAN0_TX,
|
|
||||||
Standby: machine.NoPin,
|
|
||||||
})
|
|
||||||
|
|
||||||
rxMsg := machine.CANRxBufferElement{}
|
|
||||||
|
|
||||||
for {
|
|
||||||
can1.Tx(0x123, []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, false, false)
|
|
||||||
can1.Tx(0x789, []byte{0x02, 0x24, 0x46, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, true, false)
|
|
||||||
time.Sleep(time.Millisecond * 1000)
|
|
||||||
|
|
||||||
sz0 := can0.RxFifoSize()
|
|
||||||
if sz0 > 0 {
|
|
||||||
fmt.Printf("CAN0 %d\r\n", sz0)
|
|
||||||
for i := 0; i < sz0; i++ {
|
|
||||||
can0.RxRaw(&rxMsg)
|
|
||||||
fmt.Printf("-> %08X %X %#v\r\n", rxMsg.ID, rxMsg.DLC, rxMsg.Data())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sz1 := can1.RxFifoSize()
|
|
||||||
if sz1 > 0 {
|
|
||||||
fmt.Printf("CAN1 %d\r\n", sz1)
|
|
||||||
for i := 0; i < sz1; i++ {
|
|
||||||
can1.RxRaw(&rxMsg)
|
|
||||||
fmt.Printf("-> %08X %X %#v\r\n", rxMsg.ID, rxMsg.DLC, rxMsg.Data())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
// +build feather_m4_can
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"machine"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// power on the CAN Transceiver
|
|
||||||
// https://learn.adafruit.com/adafruit-feather-m4-can-express/pinouts#can-bus-3078990-8
|
|
||||||
boost_en := machine.BOOST_EN
|
|
||||||
boost_en.Configure(machine.PinConfig{Mode: machine.PinOutput})
|
|
||||||
boost_en.High()
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"device/sam"
|
|
||||||
"fmt"
|
|
||||||
"machine"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type canMsg struct {
|
|
||||||
ch byte
|
|
||||||
id uint32
|
|
||||||
dlc byte
|
|
||||||
data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
ch := make(chan canMsg, 10)
|
|
||||||
go func() {
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case m := <-ch:
|
|
||||||
fmt.Printf("%d %03X %X ", m.ch, m.id, m.dlc)
|
|
||||||
for _, d := range m.data {
|
|
||||||
fmt.Printf("%02X ", d)
|
|
||||||
}
|
|
||||||
fmt.Printf("\r\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
can1 := machine.CAN1
|
|
||||||
can1.Configure(machine.CANConfig{
|
|
||||||
TransferRate: machine.CANTransferRate500kbps,
|
|
||||||
TransferRateFD: machine.CANTransferRate1000kbps,
|
|
||||||
Rx: machine.CAN1_RX,
|
|
||||||
Tx: machine.CAN1_TX,
|
|
||||||
Standby: machine.CAN1_STANDBY,
|
|
||||||
})
|
|
||||||
// RF0NE : Rx FIFO 0 New Message Interrupt Enable
|
|
||||||
can1.SetInterrupt(sam.CAN_IE_RF0NE, func(*machine.CAN) {
|
|
||||||
rxMsg := machine.CANRxBufferElement{}
|
|
||||||
can1.RxRaw(&rxMsg)
|
|
||||||
m := canMsg{ch: 1, id: rxMsg.ID, dlc: rxMsg.DLC, data: rxMsg.Data()}
|
|
||||||
select {
|
|
||||||
case ch <- m:
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
can0 := machine.CAN0
|
|
||||||
can0.Configure(machine.CANConfig{
|
|
||||||
TransferRate: machine.CANTransferRate500kbps,
|
|
||||||
TransferRateFD: machine.CANTransferRate1000kbps,
|
|
||||||
Rx: machine.CAN0_RX,
|
|
||||||
Tx: machine.CAN0_TX,
|
|
||||||
Standby: machine.NoPin,
|
|
||||||
})
|
|
||||||
// RF0NE : Rx FIFO 0 New Message Interrupt Enable
|
|
||||||
can0.SetInterrupt(sam.CAN_IE_RF0NE, func(*machine.CAN) {
|
|
||||||
rxMsg := machine.CANRxBufferElement{}
|
|
||||||
can0.RxRaw(&rxMsg)
|
|
||||||
m := canMsg{ch: 2, id: rxMsg.ID, dlc: rxMsg.DLC, data: rxMsg.Data()}
|
|
||||||
select {
|
|
||||||
case ch <- m:
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
for {
|
|
||||||
can0.Tx(0x123, []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}, false, false)
|
|
||||||
time.Sleep(time.Millisecond * 500)
|
|
||||||
can1.Tx(0x456, []byte{0xAA, 0xBB, 0xCC}, false, false)
|
|
||||||
time.Sleep(time.Millisecond * 1000)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
.section .text.tinygo_startTask
|
|
||||||
.global tinygo_startTask
|
|
||||||
.type tinygo_startTask, %function
|
|
||||||
tinygo_startTask:
|
|
||||||
.cfi_startproc
|
|
||||||
// Small assembly stub for starting a goroutine. This is already run on the
|
|
||||||
// new stack, with the callee-saved registers already loaded.
|
|
||||||
// Most importantly, EBX contain the pc of the to-be-started function and
|
|
||||||
// ESI contain the only argument it is given. Multiple arguments are packed
|
|
||||||
// into one by storing them in a new allocation.
|
|
||||||
|
|
||||||
// Indicate to the unwinder that there is nothing to unwind, this is the
|
|
||||||
// root frame. It avoids bogus extra frames in GDB.
|
|
||||||
.cfi_undefined eip
|
|
||||||
|
|
||||||
// Set the first argument of the goroutine start wrapper, which contains all
|
|
||||||
// the arguments.
|
|
||||||
pushl %esi
|
|
||||||
|
|
||||||
// Branch to the "goroutine start" function.
|
|
||||||
calll *%ebx
|
|
||||||
|
|
||||||
// Rebalance the stack (to undo the above push).
|
|
||||||
addl $4, %esp
|
|
||||||
|
|
||||||
// After return, exit this goroutine. This is a tail call.
|
|
||||||
jmp tinygo_pause
|
|
||||||
.cfi_endproc
|
|
||||||
|
|
||||||
.global tinygo_swapTask
|
|
||||||
.type tinygo_swapTask, %function
|
|
||||||
tinygo_swapTask:
|
|
||||||
// This function gets the following parameters:
|
|
||||||
movl 4(%esp), %eax // newStack uintptr
|
|
||||||
movl 8(%esp), %ecx // oldStack *uintptr
|
|
||||||
// More information on the calling convention:
|
|
||||||
// https://wiki.osdev.org/System_V_ABI#i386
|
|
||||||
|
|
||||||
// Save all callee-saved registers:
|
|
||||||
pushl %ebp
|
|
||||||
pushl %edi
|
|
||||||
pushl %esi
|
|
||||||
pushl %ebx
|
|
||||||
|
|
||||||
// Save the current stack pointer in oldStack.
|
|
||||||
movl %esp, (%ecx)
|
|
||||||
|
|
||||||
// Switch to the new stack pointer.
|
|
||||||
movl %eax, %esp
|
|
||||||
|
|
||||||
// Load saved register from the new stack.
|
|
||||||
popl %ebx
|
|
||||||
popl %esi
|
|
||||||
popl %edi
|
|
||||||
popl %ebp
|
|
||||||
|
|
||||||
// Return into the new task, as if tinygo_swapTask was a regular call.
|
|
||||||
ret
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
// +build scheduler.tasks,386
|
|
||||||
|
|
||||||
package task
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
var systemStack uintptr
|
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
|
||||||
// switching between tasks. Also see task_stack_386.S that relies on the exact
|
|
||||||
// layout of this struct.
|
|
||||||
type calleeSavedRegs struct {
|
|
||||||
ebx uintptr
|
|
||||||
esi uintptr
|
|
||||||
edi uintptr
|
|
||||||
ebp uintptr
|
|
||||||
|
|
||||||
pc uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
// archInit runs architecture-specific setup for the goroutine startup.
|
|
||||||
func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|
||||||
// Store the initial sp for the startTask function (implemented in assembly).
|
|
||||||
s.sp = uintptr(unsafe.Pointer(r))
|
|
||||||
|
|
||||||
// Initialize the registers.
|
|
||||||
// These will be popped off of the stack on the first resume of the goroutine.
|
|
||||||
|
|
||||||
// Start the function at tinygo_startTask (defined in
|
|
||||||
// src/internal/task/task_stack_386.S). This assembly code calls a function
|
|
||||||
// (passed in EBX) with a single argument (passed in ESI). After the
|
|
||||||
// function returns, it calls Pause().
|
|
||||||
r.pc = uintptr(unsafe.Pointer(&startTask))
|
|
||||||
|
|
||||||
// Pass the function to call in EBX.
|
|
||||||
// This function is a compiler-generated wrapper which loads arguments out
|
|
||||||
// of a struct pointer. See createGoroutineStartWrapper (defined in
|
|
||||||
// compiler/goroutine.go) for more information.
|
|
||||||
r.ebx = fn
|
|
||||||
|
|
||||||
// Pass the pointer to the arguments struct in ESI.
|
|
||||||
r.esi = uintptr(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) resume() {
|
|
||||||
swapTask(s.sp, &systemStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) pause() {
|
|
||||||
newStack := systemStack
|
|
||||||
systemStack = 0
|
|
||||||
swapTask(newStack, &s.sp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemStack returns the system stack pointer when called from a task stack.
|
|
||||||
// When called from the system stack, it returns 0.
|
|
||||||
func SystemStack() uintptr {
|
|
||||||
return systemStack
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
#ifdef __MACH__ // Darwin
|
|
||||||
.global _tinygo_startTask
|
|
||||||
_tinygo_startTask:
|
|
||||||
#else // Linux etc
|
|
||||||
.section .text.tinygo_startTask
|
|
||||||
.global tinygo_startTask
|
|
||||||
tinygo_startTask:
|
|
||||||
#endif
|
|
||||||
.cfi_startproc
|
|
||||||
// Small assembly stub for starting a goroutine. This is already run on the
|
|
||||||
// new stack, with the callee-saved registers already loaded.
|
|
||||||
// Most importantly, r12 contain the pc of the to-be-started function and
|
|
||||||
// r13 contain the only argument it is given. Multiple arguments are packed
|
|
||||||
// into one by storing them in a new allocation.
|
|
||||||
|
|
||||||
// Indicate to the unwinder that there is nothing to unwind, this is the
|
|
||||||
// root frame. It avoids bogus extra frames in GDB like here:
|
|
||||||
// #10 0x00000000004277b6 in <goroutine wrapper> () at [...]
|
|
||||||
// #11 0x00000000004278f3 in tinygo_startTask () at [...]
|
|
||||||
// #12 0x0000000000002030 in ?? ()
|
|
||||||
// #13 0x0000000000000071 in ?? ()
|
|
||||||
.cfi_undefined rip
|
|
||||||
|
|
||||||
// Set the first argument of the goroutine start wrapper, which contains all
|
|
||||||
// the arguments.
|
|
||||||
movq %r13, %rdi
|
|
||||||
|
|
||||||
// Branch to the "goroutine start" function.
|
|
||||||
callq *%r12
|
|
||||||
|
|
||||||
// After return, exit this goroutine. This is a tail call.
|
|
||||||
#ifdef __MACH__
|
|
||||||
jmp _tinygo_pause
|
|
||||||
#else
|
|
||||||
jmp tinygo_pause
|
|
||||||
#endif
|
|
||||||
.cfi_endproc
|
|
||||||
|
|
||||||
#ifdef __MACH__ // Darwin
|
|
||||||
.global _tinygo_swapTask
|
|
||||||
_tinygo_swapTask:
|
|
||||||
#else // Linux etc
|
|
||||||
.global tinygo_swapTask
|
|
||||||
.section .text.tinygo_swapTask
|
|
||||||
tinygo_swapTask:
|
|
||||||
#endif
|
|
||||||
// This function gets the following parameters:
|
|
||||||
// %rdi = newStack uintptr
|
|
||||||
// %rsi = oldStack *uintptr
|
|
||||||
|
|
||||||
// Save all callee-saved registers:
|
|
||||||
pushq %r15
|
|
||||||
pushq %r14
|
|
||||||
pushq %r13
|
|
||||||
pushq %r12
|
|
||||||
pushq %rbp
|
|
||||||
pushq %rbx
|
|
||||||
|
|
||||||
// Save the current stack pointer in oldStack.
|
|
||||||
movq %rsp, (%rsi)
|
|
||||||
|
|
||||||
// Switch to the new stack pointer.
|
|
||||||
movq %rdi, %rsp
|
|
||||||
|
|
||||||
// Load saved register from the new stack.
|
|
||||||
popq %rbx
|
|
||||||
popq %rbp
|
|
||||||
popq %r12
|
|
||||||
popq %r13
|
|
||||||
popq %r14
|
|
||||||
popq %r15
|
|
||||||
|
|
||||||
// Return into the new task, as if tinygo_swapTask was a regular call.
|
|
||||||
ret
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
// +build scheduler.tasks,amd64
|
|
||||||
|
|
||||||
package task
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
var systemStack uintptr
|
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
|
||||||
// switching between tasks. Also see task_stack_amd64.S that relies on the exact
|
|
||||||
// layout of this struct.
|
|
||||||
type calleeSavedRegs struct {
|
|
||||||
rbx uintptr
|
|
||||||
rbp uintptr
|
|
||||||
r12 uintptr
|
|
||||||
r13 uintptr
|
|
||||||
r14 uintptr
|
|
||||||
r15 uintptr
|
|
||||||
|
|
||||||
pc uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
// archInit runs architecture-specific setup for the goroutine startup.
|
|
||||||
func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|
||||||
// Store the initial sp for the startTask function (implemented in assembly).
|
|
||||||
s.sp = uintptr(unsafe.Pointer(r))
|
|
||||||
|
|
||||||
// Initialize the registers.
|
|
||||||
// These will be popped off of the stack on the first resume of the goroutine.
|
|
||||||
|
|
||||||
// Start the function at tinygo_startTask (defined in
|
|
||||||
// src/internal/task/task_stack_amd64.S). This assembly code calls a
|
|
||||||
// function (passed in r12) with a single argument (passed in r13). After
|
|
||||||
// the function returns, it calls Pause().
|
|
||||||
r.pc = uintptr(unsafe.Pointer(&startTask))
|
|
||||||
|
|
||||||
// Pass the function to call in r12.
|
|
||||||
// This function is a compiler-generated wrapper which loads arguments out
|
|
||||||
// of a struct pointer. See createGoroutineStartWrapper (defined in
|
|
||||||
// compiler/goroutine.go) for more information.
|
|
||||||
r.r12 = fn
|
|
||||||
|
|
||||||
// Pass the pointer to the arguments struct in r13.
|
|
||||||
r.r13 = uintptr(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) resume() {
|
|
||||||
swapTask(s.sp, &systemStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) pause() {
|
|
||||||
newStack := systemStack
|
|
||||||
systemStack = 0
|
|
||||||
swapTask(newStack, &s.sp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemStack returns the system stack pointer when called from a task stack.
|
|
||||||
// When called from the system stack, it returns 0.
|
|
||||||
func SystemStack() uintptr {
|
|
||||||
return systemStack
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
// Only generate .debug_frame, don't generate .eh_frame.
|
|
||||||
.cfi_sections .debug_frame
|
|
||||||
|
|
||||||
.section .text.tinygo_startTask
|
|
||||||
.global tinygo_startTask
|
|
||||||
.type tinygo_startTask, %function
|
|
||||||
tinygo_startTask:
|
|
||||||
.cfi_startproc
|
|
||||||
// Small assembly stub for starting a goroutine. This is already run on the
|
|
||||||
// new stack, with the callee-saved registers already loaded.
|
|
||||||
// Most importantly, r4 contains the pc of the to-be-started function and r5
|
|
||||||
// contains the only argument it is given. Multiple arguments are packed
|
|
||||||
// into one by storing them in a new allocation.
|
|
||||||
|
|
||||||
// Indicate to the unwinder that there is nothing to unwind, this is the
|
|
||||||
// root frame. It avoids the following (bogus) error message in GDB:
|
|
||||||
// Backtrace stopped: previous frame identical to this frame (corrupt stack?)
|
|
||||||
.cfi_undefined lr
|
|
||||||
|
|
||||||
// Set the first argument of the goroutine start wrapper, which contains all
|
|
||||||
// the arguments.
|
|
||||||
mov r0, r5
|
|
||||||
|
|
||||||
// Branch to the "goroutine start" function. By using blx instead of bx,
|
|
||||||
// we'll return here instead of tail calling.
|
|
||||||
blx r4
|
|
||||||
|
|
||||||
// After return, exit this goroutine. This is a tail call.
|
|
||||||
bl tinygo_pause
|
|
||||||
.cfi_endproc
|
|
||||||
.size tinygo_startTask, .-tinygo_startTask
|
|
||||||
|
|
||||||
.global tinygo_swapTask
|
|
||||||
.type tinygo_swapTask, %function
|
|
||||||
tinygo_swapTask:
|
|
||||||
// This function gets the following parameters:
|
|
||||||
// r0 = newStack uintptr
|
|
||||||
// r1 = oldStack *uintptr
|
|
||||||
|
|
||||||
// Save all callee-saved registers:
|
|
||||||
push {r4-r11, lr}
|
|
||||||
|
|
||||||
// Save the current stack pointer in oldStack.
|
|
||||||
str sp, [r1]
|
|
||||||
|
|
||||||
// Switch to the new stack pointer.
|
|
||||||
mov sp, r0
|
|
||||||
|
|
||||||
// Load state from new task and branch to the previous position in the
|
|
||||||
// program.
|
|
||||||
pop {r4-r11, pc}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
// +build scheduler.tasks,arm,!cortexm,!avr,!xtensa
|
|
||||||
|
|
||||||
package task
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
var systemStack uintptr
|
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
|
||||||
// switching between tasks. Also see task_stack_arm.S that relies on the exact
|
|
||||||
// layout of this struct.
|
|
||||||
type calleeSavedRegs struct {
|
|
||||||
r4 uintptr
|
|
||||||
r5 uintptr
|
|
||||||
r6 uintptr
|
|
||||||
r7 uintptr
|
|
||||||
r8 uintptr
|
|
||||||
r9 uintptr
|
|
||||||
r10 uintptr
|
|
||||||
r11 uintptr
|
|
||||||
|
|
||||||
pc uintptr
|
|
||||||
}
|
|
||||||
|
|
||||||
// archInit runs architecture-specific setup for the goroutine startup.
|
|
||||||
func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|
||||||
// Store the initial sp for the startTask function (implemented in assembly).
|
|
||||||
s.sp = uintptr(unsafe.Pointer(r))
|
|
||||||
|
|
||||||
// Initialize the registers.
|
|
||||||
// These will be popped off of the stack on the first resume of the goroutine.
|
|
||||||
|
|
||||||
// Start the function at tinygo_startTask (defined in src/internal/task/task_stack_arm.S).
|
|
||||||
// This assembly code calls a function (passed in r4) with a single argument
|
|
||||||
// (passed in r5). After the function returns, it calls Pause().
|
|
||||||
r.pc = uintptr(unsafe.Pointer(&startTask))
|
|
||||||
|
|
||||||
// Pass the function to call in r4.
|
|
||||||
// This function is a compiler-generated wrapper which loads arguments out of a struct pointer.
|
|
||||||
// See createGoroutineStartWrapper (defined in compiler/goroutine.go) for more information.
|
|
||||||
r.r4 = fn
|
|
||||||
|
|
||||||
// Pass the pointer to the arguments struct in r5.
|
|
||||||
r.r5 = uintptr(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) resume() {
|
|
||||||
swapTask(s.sp, &systemStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) pause() {
|
|
||||||
newStack := systemStack
|
|
||||||
systemStack = 0
|
|
||||||
swapTask(newStack, &s.sp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemStack returns the system stack pointer when called from a task stack.
|
|
||||||
// When called from the system stack, it returns 0.
|
|
||||||
func SystemStack() uintptr {
|
|
||||||
return systemStack
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
.section .text.tinygo_startTask
|
|
||||||
.global tinygo_startTask
|
|
||||||
.type tinygo_startTask, %function
|
|
||||||
tinygo_startTask:
|
|
||||||
.cfi_startproc
|
|
||||||
// Small assembly stub for starting a goroutine. This is already run on the
|
|
||||||
// new stack, with the callee-saved registers already loaded.
|
|
||||||
// Most importantly, x19 contains the pc of the to-be-started function and
|
|
||||||
// x20 contains the only argument it is given. Multiple arguments are packed
|
|
||||||
// into one by storing them in a new allocation.
|
|
||||||
|
|
||||||
// Indicate to the unwinder that there is nothing to unwind, this is the
|
|
||||||
// root frame. It avoids the following (bogus) error message in GDB:
|
|
||||||
// Backtrace stopped: previous frame identical to this frame (corrupt stack?)
|
|
||||||
.cfi_undefined lr
|
|
||||||
|
|
||||||
// Set the first argument of the goroutine start wrapper, which contains all
|
|
||||||
// the arguments.
|
|
||||||
mov x0, x20
|
|
||||||
|
|
||||||
// Branch to the "goroutine start" function. By using blx instead of bx,
|
|
||||||
// we'll return here instead of tail calling.
|
|
||||||
blr x19
|
|
||||||
|
|
||||||
// After return, exit this goroutine. This is a tail call.
|
|
||||||
b tinygo_pause
|
|
||||||
.cfi_endproc
|
|
||||||
.size tinygo_startTask, .-tinygo_startTask
|
|
||||||
|
|
||||||
.global tinygo_swapTask
|
|
||||||
.type tinygo_swapTask, %function
|
|
||||||
tinygo_swapTask:
|
|
||||||
// This function gets the following parameters:
|
|
||||||
// x0 = newStack uintptr
|
|
||||||
// x1 = oldStack *uintptr
|
|
||||||
|
|
||||||
// Save all callee-saved registers:
|
|
||||||
stp x19, x20, [sp, #-96]!
|
|
||||||
stp x21, x22, [sp, #16]
|
|
||||||
stp x23, x24, [sp, #32]
|
|
||||||
stp x25, x26, [sp, #48]
|
|
||||||
stp x27, x28, [sp, #64]
|
|
||||||
stp x29, x30, [sp, #80]
|
|
||||||
|
|
||||||
// Save the current stack pointer in oldStack.
|
|
||||||
mov x8, sp
|
|
||||||
str x8, [x1]
|
|
||||||
|
|
||||||
// Switch to the new stack pointer.
|
|
||||||
mov sp, x0
|
|
||||||
|
|
||||||
// Restore stack state and return.
|
|
||||||
ldp x29, x30, [sp, #80]
|
|
||||||
ldp x27, x28, [sp, #64]
|
|
||||||
ldp x25, x26, [sp, #48]
|
|
||||||
ldp x23, x24, [sp, #32]
|
|
||||||
ldp x21, x22, [sp, #16]
|
|
||||||
ldp x19, x20, [sp], #96
|
|
||||||
ret
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
// +build scheduler.tasks,arm64
|
|
||||||
|
|
||||||
package task
|
|
||||||
|
|
||||||
import "unsafe"
|
|
||||||
|
|
||||||
var systemStack uintptr
|
|
||||||
|
|
||||||
// calleeSavedRegs is the list of registers that must be saved and restored when
|
|
||||||
// switching between tasks. Also see task_stack_arm64.S that relies on the exact
|
|
||||||
// layout of this struct.
|
|
||||||
type calleeSavedRegs struct {
|
|
||||||
x19 uintptr
|
|
||||||
x20 uintptr
|
|
||||||
x21 uintptr
|
|
||||||
x22 uintptr
|
|
||||||
x23 uintptr
|
|
||||||
x24 uintptr
|
|
||||||
x25 uintptr
|
|
||||||
x26 uintptr
|
|
||||||
x27 uintptr
|
|
||||||
x28 uintptr
|
|
||||||
x29 uintptr
|
|
||||||
|
|
||||||
pc uintptr // aka x30 aka LR
|
|
||||||
}
|
|
||||||
|
|
||||||
// archInit runs architecture-specific setup for the goroutine startup.
|
|
||||||
func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
|
|
||||||
// Store the initial sp for the startTask function (implemented in assembly).
|
|
||||||
s.sp = uintptr(unsafe.Pointer(r))
|
|
||||||
|
|
||||||
// Initialize the registers.
|
|
||||||
// These will be popped off of the stack on the first resume of the goroutine.
|
|
||||||
|
|
||||||
// Start the function at tinygo_startTask (defined in src/internal/task/task_stack_arm64.S).
|
|
||||||
// This assembly code calls a function (passed in x19) with a single argument
|
|
||||||
// (passed in x20). After the function returns, it calls Pause().
|
|
||||||
r.pc = uintptr(unsafe.Pointer(&startTask))
|
|
||||||
|
|
||||||
// Pass the function to call in x19.
|
|
||||||
// This function is a compiler-generated wrapper which loads arguments out of a struct pointer.
|
|
||||||
// See createGoroutineStartWrapper (defined in compiler/goroutine.go) for more information.
|
|
||||||
r.x19 = fn
|
|
||||||
|
|
||||||
// Pass the pointer to the arguments struct in x20.
|
|
||||||
r.x20 = uintptr(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) resume() {
|
|
||||||
swapTask(s.sp, &systemStack)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *state) pause() {
|
|
||||||
newStack := systemStack
|
|
||||||
systemStack = 0
|
|
||||||
swapTask(newStack, &s.sp)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemStack returns the system stack pointer when called from a task stack.
|
|
||||||
// When called from the system stack, it returns 0.
|
|
||||||
func SystemStack() uintptr {
|
|
||||||
return systemStack
|
|
||||||
}
|
|
||||||
@@ -2,12 +2,6 @@
|
|||||||
|
|
||||||
package task
|
package task
|
||||||
|
|
||||||
// Note that this is almost the same as task_stack_arm.go, but it uses the MSP
|
|
||||||
// register to store the system stack pointer instead of a global variable. The
|
|
||||||
// big advantage of this is that interrupts always execute with MSP (and not
|
|
||||||
// PSP, which is used for goroutines) so that goroutines do not need extra stack
|
|
||||||
// space for interrupts.
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/arm"
|
"device/arm"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|||||||
@@ -328,14 +328,3 @@ var (
|
|||||||
SERCOM: 6,
|
SERCOM: 6,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// CAN on the SAM E54 Xplained Pro
|
|
||||||
var (
|
|
||||||
CAN0 = CAN{
|
|
||||||
Bus: sam.CAN0,
|
|
||||||
}
|
|
||||||
|
|
||||||
CAN1 = CAN{
|
|
||||||
Bus: sam.CAN1,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ func init() {
|
|||||||
D7.High()
|
D7.High()
|
||||||
}
|
}
|
||||||
|
|
||||||
// I2C on the Feather M4 CAN.
|
// I2C on the Feather M4.
|
||||||
var (
|
var (
|
||||||
I2C0 = &I2C{
|
I2C0 = &I2C{
|
||||||
Bus: sam.SERCOM2_I2CM,
|
Bus: sam.SERCOM2_I2CM,
|
||||||
@@ -133,21 +133,10 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI on the Feather M4 CAN.
|
// SPI on the Feather M4.
|
||||||
var (
|
var (
|
||||||
SPI0 = SPI{
|
SPI0 = SPI{
|
||||||
Bus: sam.SERCOM1_SPIM,
|
Bus: sam.SERCOM1_SPIM,
|
||||||
SERCOM: 1,
|
SERCOM: 1,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// CAN on the Feather M4 CAN.
|
|
||||||
var (
|
|
||||||
CAN0 = CAN{
|
|
||||||
Bus: sam.CAN0,
|
|
||||||
}
|
|
||||||
|
|
||||||
CAN1 = CAN{
|
|
||||||
Bus: sam.CAN1,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ const (
|
|||||||
// I2C on the QT Py M0.
|
// I2C on the QT Py M0.
|
||||||
var (
|
var (
|
||||||
I2C0 = &I2C{
|
I2C0 = &I2C{
|
||||||
Bus: sam.SERCOM1_I2CM,
|
Bus: sam.SERCOM2_I2CM,
|
||||||
SERCOM: 1,
|
SERCOM: 2,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,6 @@ var (
|
|||||||
ErrNoPinChangeChannel = errors.New("machine: no channel available for pin interrupt")
|
ErrNoPinChangeChannel = errors.New("machine: no channel available for pin interrupt")
|
||||||
)
|
)
|
||||||
|
|
||||||
// PinMode sets the direction and pull mode of the pin. For example, PinOutput
|
|
||||||
// sets the pin as an output and PinInputPullup sets the pin as an input with a
|
|
||||||
// pull-up.
|
|
||||||
type PinMode uint8
|
|
||||||
|
|
||||||
type PinConfig struct {
|
type PinConfig struct {
|
||||||
Mode PinMode
|
Mode PinMode
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
package machine
|
package machine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"device"
|
||||||
"device/arm"
|
"device/arm"
|
||||||
"device/sam"
|
"device/sam"
|
||||||
"errors"
|
"errors"
|
||||||
@@ -16,6 +17,8 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PinAnalog PinMode = 1
|
PinAnalog PinMode = 1
|
||||||
PinSERCOM PinMode = 2
|
PinSERCOM PinMode = 2
|
||||||
@@ -430,18 +433,7 @@ func (a ADC) Get() uint16 {
|
|||||||
sam.ADC.CTRLA.ClearBits(sam.ADC_CTRLA_ENABLE)
|
sam.ADC.CTRLA.ClearBits(sam.ADC_CTRLA_ENABLE)
|
||||||
waitADCSync()
|
waitADCSync()
|
||||||
|
|
||||||
// scales to 16-bit result
|
return uint16(val) << 4 // scales from 12 to 16-bit result
|
||||||
switch (sam.ADC.CTRLB.Get() & sam.ADC_CTRLB_RESSEL_Msk) >> sam.ADC_CTRLB_RESSEL_Pos {
|
|
||||||
case sam.ADC_CTRLB_RESSEL_8BIT:
|
|
||||||
val = val << 8
|
|
||||||
case sam.ADC_CTRLB_RESSEL_10BIT:
|
|
||||||
val = val << 6
|
|
||||||
case sam.ADC_CTRLB_RESSEL_16BIT:
|
|
||||||
val = val << 4
|
|
||||||
case sam.ADC_CTRLB_RESSEL_12BIT:
|
|
||||||
val = val << 4
|
|
||||||
}
|
|
||||||
return val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a ADC) getADCChannel() uint8 {
|
func (a ADC) getADCChannel() uint8 {
|
||||||
@@ -1298,21 +1290,43 @@ var (
|
|||||||
// spi.Tx(nil, rx)
|
// spi.Tx(nil, rx)
|
||||||
//
|
//
|
||||||
func (spi SPI) Tx(w, r []byte) error {
|
func (spi SPI) Tx(w, r []byte) error {
|
||||||
switch {
|
if spi.Bus.BAUD.Get() == 0x00 {
|
||||||
case w == nil:
|
// When the SPI Freq is 24MHz, special processing is performed to improve the speed.
|
||||||
// read only, so write zero and read a result.
|
|
||||||
spi.rx(r)
|
|
||||||
case r == nil:
|
|
||||||
// write only
|
|
||||||
spi.tx(w)
|
|
||||||
|
|
||||||
default:
|
switch {
|
||||||
// write/read
|
case w == nil:
|
||||||
if len(w) != len(r) {
|
// read only, so write zero and read a result.
|
||||||
return ErrTxInvalidSliceSize
|
spi.rx(r)
|
||||||
|
case r == nil:
|
||||||
|
// write only
|
||||||
|
spi.tx24mhz(w)
|
||||||
|
|
||||||
|
default:
|
||||||
|
// write/read
|
||||||
|
if len(w) != len(r) {
|
||||||
|
return ErrTxInvalidSliceSize
|
||||||
|
}
|
||||||
|
|
||||||
|
spi.txrx24mhz(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
spi.txrx(w, r)
|
} else {
|
||||||
|
switch {
|
||||||
|
case w == nil:
|
||||||
|
// read only, so write zero and read a result.
|
||||||
|
spi.rx(r)
|
||||||
|
case r == nil:
|
||||||
|
// write only
|
||||||
|
spi.tx(w)
|
||||||
|
|
||||||
|
default:
|
||||||
|
// write/read
|
||||||
|
if len(w) != len(r) {
|
||||||
|
return ErrTxInvalidSliceSize
|
||||||
|
}
|
||||||
|
|
||||||
|
spi.txrx(w, r)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -1365,6 +1379,48 @@ func (spi SPI) txrx(tx, rx []byte) {
|
|||||||
rx[len(rx)-1] = byte(spi.Bus.DATA.Get())
|
rx[len(rx)-1] = byte(spi.Bus.DATA.Get())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tx24mhz is a special tx/rx function for CPU Clock 48 Mhz and SPI Freq 24 Mhz
|
||||||
|
func (spi SPI) tx24mhz(tx []byte) {
|
||||||
|
spi.Bus.DATA.Set(uint32(tx[0]))
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
|
||||||
|
for i := 1; i < len(tx); i++ {
|
||||||
|
spi.Bus.DATA.Set(uint32(tx[i]))
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
spi.Bus.DATA.Get()
|
||||||
|
}
|
||||||
|
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_RXC) {
|
||||||
|
}
|
||||||
|
spi.Bus.DATA.Get()
|
||||||
|
}
|
||||||
|
|
||||||
|
// txrx24mhz is a special tx/rx function for CPU Clock 48 Mhz and SPI Freq 24 Mhz
|
||||||
|
func (spi SPI) txrx24mhz(tx, rx []byte) {
|
||||||
|
spi.Bus.DATA.Set(uint32(tx[0]))
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
|
||||||
|
for i := 1; i < len(rx); i++ {
|
||||||
|
spi.Bus.DATA.Set(uint32(tx[i]))
|
||||||
|
device.Asm("nop")
|
||||||
|
device.Asm("nop")
|
||||||
|
rx[i-1] = byte(spi.Bus.DATA.Get())
|
||||||
|
}
|
||||||
|
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPI_INTFLAG_RXC) {
|
||||||
|
}
|
||||||
|
rx[len(rx)-1] = byte(spi.Bus.DATA.Get())
|
||||||
|
}
|
||||||
|
|
||||||
// TCC is one timer/counter peripheral, which consists of a counter and multiple
|
// TCC is one timer/counter peripheral, which consists of a counter and multiple
|
||||||
// output channels (that can be connected to actual pins). You can set the
|
// output channels (that can be connected to actual pins). You can set the
|
||||||
// frequency using SetPeriod, but only for all the channels in this TCC
|
// frequency using SetPeriod, but only for all the channels in this TCC
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build sam,atsamd51 sam,atsame5x
|
// +build sam,atsamd51
|
||||||
|
|
||||||
// Peripheral abstraction layer for the atsamd51.
|
// Peripheral abstraction layer for the atsamd51.
|
||||||
//
|
//
|
||||||
@@ -20,6 +20,8 @@ func CPUFrequency() uint32 {
|
|||||||
return 120000000
|
return 120000000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PinAnalog PinMode = 1
|
PinAnalog PinMode = 1
|
||||||
PinSERCOM PinMode = 2
|
PinSERCOM PinMode = 2
|
||||||
@@ -42,9 +44,6 @@ const (
|
|||||||
PinTCCF PinMode = PinTimerAlt
|
PinTCCF PinMode = PinTimerAlt
|
||||||
PinTCCG PinMode = PinTCCPDEC
|
PinTCCG PinMode = PinTCCPDEC
|
||||||
PinInputPulldown PinMode = 18
|
PinInputPulldown PinMode = 18
|
||||||
PinCAN PinMode = 19
|
|
||||||
PinCAN0 PinMode = PinSDHC
|
|
||||||
PinCAN1 PinMode = PinCom
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PinChange uint8
|
type PinChange uint8
|
||||||
@@ -628,18 +627,6 @@ func (p Pin) Configure(config PinConfig) {
|
|||||||
}
|
}
|
||||||
// enable port config
|
// enable port config
|
||||||
p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN | sam.PORT_GROUP_PINCFG_DRVSTR)
|
p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN | sam.PORT_GROUP_PINCFG_DRVSTR)
|
||||||
case PinSDHC:
|
|
||||||
if p&1 > 0 {
|
|
||||||
// odd pin, so save the even pins
|
|
||||||
val := p.getPMux() & sam.PORT_GROUP_PMUX_PMUXE_Msk
|
|
||||||
p.setPMux(val | (uint8(PinSDHC) << 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 | (uint8(PinSDHC) << sam.PORT_GROUP_PMUX_PMUXE_Pos))
|
|
||||||
}
|
|
||||||
// enable port config
|
|
||||||
p.setPinCfg(sam.PORT_GROUP_PINCFG_PMUXEN)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -861,18 +848,7 @@ func (a ADC) Get() uint16 {
|
|||||||
for bus.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_ENABLE) {
|
for bus.SYNCBUSY.HasBits(sam.ADC_SYNCBUSY_ENABLE) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// scales to 16-bit result
|
return uint16(val) << 4 // scales from 12 to 16-bit result
|
||||||
switch (bus.CTRLB.Get() & sam.ADC_CTRLB_RESSEL_Msk) >> sam.ADC_CTRLB_RESSEL_Pos {
|
|
||||||
case sam.ADC_CTRLB_RESSEL_8BIT:
|
|
||||||
val = val << 8
|
|
||||||
case sam.ADC_CTRLB_RESSEL_10BIT:
|
|
||||||
val = val << 6
|
|
||||||
case sam.ADC_CTRLB_RESSEL_16BIT:
|
|
||||||
val = val << 4
|
|
||||||
case sam.ADC_CTRLB_RESSEL_12BIT:
|
|
||||||
val = val << 4
|
|
||||||
}
|
|
||||||
return val
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a ADC) getADCBus() *sam.ADC_Type {
|
func (a ADC) getADCBus() *sam.ADC_Type {
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,468 +0,0 @@
|
|||||||
// +build sam,atsame51 sam,atsame54
|
|
||||||
|
|
||||||
package machine
|
|
||||||
|
|
||||||
import (
|
|
||||||
"device/sam"
|
|
||||||
"errors"
|
|
||||||
"runtime/interrupt"
|
|
||||||
"unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
CANRxFifoSize = 16
|
|
||||||
CANTxFifoSize = 16
|
|
||||||
CANEvFifoSize = 16
|
|
||||||
)
|
|
||||||
|
|
||||||
// Message RAM can only be located in the first 64 KB area of the system RAM.
|
|
||||||
// TODO: when the go:section pragma is merged, add the section configuration
|
|
||||||
|
|
||||||
//go:align 4
|
|
||||||
var CANRxFifo [2][(8 + 64) * CANRxFifoSize]byte
|
|
||||||
|
|
||||||
//go:align 4
|
|
||||||
var CANTxFifo [2][(8 + 64) * CANTxFifoSize]byte
|
|
||||||
|
|
||||||
//go:align 4
|
|
||||||
var CANEvFifo [2][(8) * CANEvFifoSize]byte
|
|
||||||
|
|
||||||
type CAN struct {
|
|
||||||
Bus *sam.CAN_Type
|
|
||||||
}
|
|
||||||
|
|
||||||
type CANTransferRate uint32
|
|
||||||
|
|
||||||
// CAN transfer rates for CANConfig
|
|
||||||
const (
|
|
||||||
CANTransferRate125kbps CANTransferRate = 125000
|
|
||||||
CANTransferRate250kbps CANTransferRate = 250000
|
|
||||||
CANTransferRate500kbps CANTransferRate = 500000
|
|
||||||
CANTransferRate1000kbps CANTransferRate = 1000000
|
|
||||||
CANTransferRate2000kbps CANTransferRate = 2000000
|
|
||||||
CANTransferRate4000kbps CANTransferRate = 4000000
|
|
||||||
)
|
|
||||||
|
|
||||||
// CANConfig holds CAN configuration parameters. Tx and Rx need to be
|
|
||||||
// specified with some pins. When the Standby Pin is specified, configure it
|
|
||||||
// as an output pin and output Low in Configure(). If this operation is not
|
|
||||||
// necessary, specify NoPin.
|
|
||||||
type CANConfig struct {
|
|
||||||
TransferRate CANTransferRate
|
|
||||||
TransferRateFD CANTransferRate
|
|
||||||
Tx Pin
|
|
||||||
Rx Pin
|
|
||||||
Standby Pin
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
errCANInvalidTransferRate = errors.New("CAN: invalid TransferRate")
|
|
||||||
errCANInvalidTransferRateFD = errors.New("CAN: invalid TransferRateFD")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Configure this CAN peripheral with the given configuration.
|
|
||||||
func (can *CAN) Configure(config CANConfig) error {
|
|
||||||
if config.Standby != NoPin {
|
|
||||||
config.Standby.Configure(PinConfig{Mode: PinOutput})
|
|
||||||
config.Standby.Low()
|
|
||||||
}
|
|
||||||
|
|
||||||
mode := PinCAN0
|
|
||||||
if can.instance() == 1 {
|
|
||||||
mode = PinCAN1
|
|
||||||
}
|
|
||||||
|
|
||||||
config.Rx.Configure(PinConfig{Mode: mode})
|
|
||||||
config.Tx.Configure(PinConfig{Mode: mode})
|
|
||||||
|
|
||||||
can.Bus.CCCR.SetBits(sam.CAN_CCCR_INIT)
|
|
||||||
for !can.Bus.CCCR.HasBits(sam.CAN_CCCR_INIT) {
|
|
||||||
}
|
|
||||||
|
|
||||||
can.Bus.CCCR.SetBits(sam.CAN_CCCR_CCE)
|
|
||||||
|
|
||||||
can.Bus.CCCR.SetBits(sam.CAN_CCCR_BRSE | sam.CAN_CCCR_FDOE)
|
|
||||||
can.Bus.MRCFG.Set(sam.CAN_MRCFG_QOS_MEDIUM)
|
|
||||||
// base clock == 48 MHz
|
|
||||||
if config.TransferRate == 0 {
|
|
||||||
config.TransferRate = CANTransferRate500kbps
|
|
||||||
}
|
|
||||||
brp := uint32(6)
|
|
||||||
switch config.TransferRate {
|
|
||||||
case CANTransferRate125kbps:
|
|
||||||
brp = 32
|
|
||||||
case CANTransferRate250kbps:
|
|
||||||
brp = 16
|
|
||||||
case CANTransferRate500kbps:
|
|
||||||
brp = 8
|
|
||||||
case CANTransferRate1000kbps:
|
|
||||||
brp = 4
|
|
||||||
default:
|
|
||||||
return errCANInvalidTransferRate
|
|
||||||
}
|
|
||||||
can.Bus.NBTP.Set(8<<sam.CAN_NBTP_NTSEG1_Pos | (brp-1)<<sam.CAN_NBTP_NBRP_Pos |
|
|
||||||
1<<sam.CAN_NBTP_NTSEG2_Pos | 3<<sam.CAN_NBTP_NSJW_Pos)
|
|
||||||
|
|
||||||
if config.TransferRateFD == 0 {
|
|
||||||
config.TransferRateFD = CANTransferRate1000kbps
|
|
||||||
}
|
|
||||||
if config.TransferRateFD < config.TransferRate {
|
|
||||||
return errCANInvalidTransferRateFD
|
|
||||||
}
|
|
||||||
brp = uint32(2)
|
|
||||||
switch config.TransferRateFD {
|
|
||||||
case CANTransferRate125kbps:
|
|
||||||
brp = 32
|
|
||||||
case CANTransferRate250kbps:
|
|
||||||
brp = 16
|
|
||||||
case CANTransferRate500kbps:
|
|
||||||
brp = 8
|
|
||||||
case CANTransferRate1000kbps:
|
|
||||||
brp = 4
|
|
||||||
case CANTransferRate2000kbps:
|
|
||||||
brp = 2
|
|
||||||
case CANTransferRate4000kbps:
|
|
||||||
brp = 1
|
|
||||||
default:
|
|
||||||
return errCANInvalidTransferRateFD
|
|
||||||
}
|
|
||||||
can.Bus.DBTP.Set((brp-1)<<sam.CAN_DBTP_DBRP_Pos | 8<<sam.CAN_DBTP_DTSEG1_Pos |
|
|
||||||
1<<sam.CAN_DBTP_DTSEG2_Pos | 3<<sam.CAN_DBTP_DSJW_Pos)
|
|
||||||
|
|
||||||
can.Bus.RXF0C.Set(sam.CAN_RXF0C_F0OM | CANRxFifoSize<<sam.CAN_RXF0C_F0S_Pos | uint32(uintptr(unsafe.Pointer(&CANRxFifo[can.instance()][0])))&0xFFFF)
|
|
||||||
can.Bus.RXESC.Set(sam.CAN_RXESC_F0DS_DATA64)
|
|
||||||
can.Bus.TXESC.Set(sam.CAN_TXESC_TBDS_DATA64)
|
|
||||||
can.Bus.TXBC.Set(CANTxFifoSize<<sam.CAN_TXBC_TFQS_Pos | 0<<sam.CAN_TXBC_NDTB_Pos | uint32(uintptr(unsafe.Pointer(&CANTxFifo[can.instance()][0])))&0xFFFF)
|
|
||||||
can.Bus.TXEFC.Set(CANEvFifoSize<<sam.CAN_TXEFC_EFS_Pos | uint32(uintptr(unsafe.Pointer(&CANEvFifo[can.instance()][0])))&0xFFFF)
|
|
||||||
|
|
||||||
can.Bus.TSCC.Set(sam.CAN_TSCC_TSS_INC)
|
|
||||||
|
|
||||||
can.Bus.GFC.Set(0<<sam.CAN_GFC_ANFS_Pos | 0<<sam.CAN_GFC_ANFE_Pos)
|
|
||||||
|
|
||||||
can.Bus.SIDFC.Set(0 << sam.CAN_SIDFC_LSS_Pos)
|
|
||||||
can.Bus.XIDFC.Set(0 << sam.CAN_SIDFC_LSS_Pos)
|
|
||||||
|
|
||||||
can.Bus.XIDAM.Set(0x1FFFFFFF << sam.CAN_XIDAM_EIDM_Pos)
|
|
||||||
|
|
||||||
can.Bus.ILE.SetBits(sam.CAN_ILE_EINT0)
|
|
||||||
|
|
||||||
can.Bus.CCCR.ClearBits(sam.CAN_CCCR_CCE)
|
|
||||||
can.Bus.CCCR.ClearBits(sam.CAN_CCCR_INIT)
|
|
||||||
for can.Bus.CCCR.HasBits(sam.CAN_CCCR_INIT) {
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Callbacks to be called for CAN.SetInterrupt(). Wre're using the magic
|
|
||||||
// constant 2 and 32 here beacuse th SAM E51/E54 has 2 CAN and 32 interrupt
|
|
||||||
// sources.
|
|
||||||
var (
|
|
||||||
canInstances [2]*CAN
|
|
||||||
canCallbacks [2][32]func(*CAN)
|
|
||||||
)
|
|
||||||
|
|
||||||
// SetInterrupt sets an interrupt to be executed when a particular CAN state.
|
|
||||||
//
|
|
||||||
// This call will replace a previously set callback. You can pass a nil func
|
|
||||||
// to unset the CAN interrupt. If you do so, the change parameter is ignored
|
|
||||||
// and can be set to any value (such as 0).
|
|
||||||
func (can *CAN) SetInterrupt(ie uint32, callback func(*CAN)) error {
|
|
||||||
if callback == nil {
|
|
||||||
// Disable this CAN interrupt
|
|
||||||
can.Bus.IE.ClearBits(ie)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
can.Bus.IE.SetBits(ie)
|
|
||||||
|
|
||||||
idx := 0
|
|
||||||
switch can.Bus {
|
|
||||||
case sam.CAN0:
|
|
||||||
canInstances[0] = can
|
|
||||||
case sam.CAN1:
|
|
||||||
canInstances[1] = can
|
|
||||||
idx = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := uint(0); i < 32; i++ {
|
|
||||||
if ie&(1<<i) != 0 {
|
|
||||||
canCallbacks[idx][i] = callback
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch can.Bus {
|
|
||||||
case sam.CAN0:
|
|
||||||
interrupt.New(sam.IRQ_CAN0, func(interrupt.Interrupt) {
|
|
||||||
ir := sam.CAN0.IR.Get()
|
|
||||||
sam.CAN0.IR.Set(ir) // clear interrupt
|
|
||||||
for i := uint(0); i < 32; i++ {
|
|
||||||
if ir&(1<<i) != 0 && canCallbacks[0][i] != nil {
|
|
||||||
canCallbacks[0][i](canInstances[0])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).Enable()
|
|
||||||
case sam.CAN1:
|
|
||||||
interrupt.New(sam.IRQ_CAN1, func(interrupt.Interrupt) {
|
|
||||||
ir := sam.CAN1.IR.Get()
|
|
||||||
sam.CAN1.IR.Set(ir) // clear interrupt
|
|
||||||
for i := uint(0); i < 32; i++ {
|
|
||||||
if ir&(1<<i) != 0 && canCallbacks[1][i] != nil {
|
|
||||||
canCallbacks[1][i](canInstances[1])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}).Enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TxFifoIsFull returns whether TxFifo is full or not.
|
|
||||||
func (can *CAN) TxFifoIsFull() bool {
|
|
||||||
return (can.Bus.TXFQS.Get() & sam.CAN_TXFQS_TFQF_Msk) == sam.CAN_TXFQS_TFQF_Msk
|
|
||||||
}
|
|
||||||
|
|
||||||
// TxRaw sends a CAN Frame according to CANTxBufferElement.
|
|
||||||
func (can *CAN) TxRaw(e *CANTxBufferElement) {
|
|
||||||
putIndex := (can.Bus.TXFQS.Get() & sam.CAN_TXFQS_TFQPI_Msk) >> sam.CAN_TXFQS_TFQPI_Pos
|
|
||||||
|
|
||||||
f := CANTxFifo[can.instance()][putIndex*(8+64) : (putIndex+1)*(8+64)]
|
|
||||||
id := e.ID
|
|
||||||
if !e.XTD {
|
|
||||||
// standard identifier is stored into ID[28:18]
|
|
||||||
id <<= 18
|
|
||||||
}
|
|
||||||
|
|
||||||
f[3] = byte(id >> 24)
|
|
||||||
if e.ESI {
|
|
||||||
f[3] |= 0x80
|
|
||||||
}
|
|
||||||
if e.XTD {
|
|
||||||
f[3] |= 0x40
|
|
||||||
}
|
|
||||||
if e.RTR {
|
|
||||||
f[3] |= 0x20
|
|
||||||
}
|
|
||||||
f[2] = byte(id >> 16)
|
|
||||||
f[1] = byte(id >> 8)
|
|
||||||
f[0] = byte(0)
|
|
||||||
f[7] = e.MM
|
|
||||||
f[6] = e.DLC
|
|
||||||
if e.EFC {
|
|
||||||
f[6] |= 0x80
|
|
||||||
}
|
|
||||||
if e.FDF {
|
|
||||||
f[6] |= 0x20
|
|
||||||
}
|
|
||||||
if e.BRS {
|
|
||||||
f[6] |= 0x10
|
|
||||||
}
|
|
||||||
f[5] = 0x00 // reserved
|
|
||||||
f[4] = 0x00 // reserved
|
|
||||||
|
|
||||||
length := CANDlcToLength(e.DLC, e.FDF)
|
|
||||||
for i := byte(0); i < length; i++ {
|
|
||||||
f[8+i] = e.DB[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
can.Bus.TXBAR.SetBits(1 << putIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
// The Tx transmits CAN frames. It is easier to use than TxRaw, but not as
|
|
||||||
// flexible.
|
|
||||||
func (can *CAN) Tx(id uint32, data []byte, isFD, isExtendedID bool) {
|
|
||||||
length := byte(len(data))
|
|
||||||
dlc := CANLengthToDlc(length, true)
|
|
||||||
|
|
||||||
e := CANTxBufferElement{
|
|
||||||
ESI: false,
|
|
||||||
XTD: isExtendedID,
|
|
||||||
RTR: false,
|
|
||||||
ID: id,
|
|
||||||
MM: 0x00,
|
|
||||||
EFC: true,
|
|
||||||
FDF: isFD,
|
|
||||||
BRS: isFD,
|
|
||||||
DLC: dlc,
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isFD {
|
|
||||||
if length > 8 {
|
|
||||||
length = 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i := byte(0); i < length; i++ {
|
|
||||||
e.DB[i] = data[i]
|
|
||||||
}
|
|
||||||
|
|
||||||
can.TxRaw(&e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RxFifoSize returns the number of CAN Frames currently stored in the RXFifo.
|
|
||||||
func (can *CAN) RxFifoSize() int {
|
|
||||||
sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos
|
|
||||||
return int(sz)
|
|
||||||
}
|
|
||||||
|
|
||||||
// RxFifoIsFull returns whether RxFifo is full or not.
|
|
||||||
func (can *CAN) RxFifoIsFull() bool {
|
|
||||||
sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos
|
|
||||||
return sz == CANRxFifoSize
|
|
||||||
}
|
|
||||||
|
|
||||||
// RxFifoIsEmpty returns whether RxFifo is empty or not.
|
|
||||||
func (can *CAN) RxFifoIsEmpty() bool {
|
|
||||||
sz := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0FL_Msk) >> sam.CAN_RXF0S_F0FL_Pos
|
|
||||||
return sz == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// RxRaw copies the received CAN frame to CANRxBufferElement.
|
|
||||||
func (can *CAN) RxRaw(e *CANRxBufferElement) {
|
|
||||||
idx := (can.Bus.RXF0S.Get() & sam.CAN_RXF0S_F0GI_Msk) >> sam.CAN_RXF0S_F0GI_Pos
|
|
||||||
f := CANRxFifo[can.instance()][idx*(8+64):]
|
|
||||||
|
|
||||||
e.ESI = false
|
|
||||||
if (f[3] & 0x80) != 0x00 {
|
|
||||||
e.ESI = true
|
|
||||||
}
|
|
||||||
|
|
||||||
e.XTD = false
|
|
||||||
if (f[3] & 0x40) != 0x00 {
|
|
||||||
e.XTD = true
|
|
||||||
}
|
|
||||||
|
|
||||||
e.RTR = false
|
|
||||||
if (f[3] & 0x20) != 0x00 {
|
|
||||||
e.RTR = true
|
|
||||||
}
|
|
||||||
|
|
||||||
id := ((uint32(f[3]) << 24) + (uint32(f[2]) << 16) + (uint32(f[1]) << 8) + uint32(f[0])) & 0x1FFFFFFF
|
|
||||||
if (f[3] & 0x20) == 0 {
|
|
||||||
id >>= 18
|
|
||||||
id &= 0x000007FF
|
|
||||||
}
|
|
||||||
e.ID = id
|
|
||||||
|
|
||||||
e.ANMF = false
|
|
||||||
if (f[7] & 0x80) != 0x00 {
|
|
||||||
e.ANMF = true
|
|
||||||
}
|
|
||||||
|
|
||||||
e.FIDX = f[7] & 0x7F
|
|
||||||
|
|
||||||
e.FDF = false
|
|
||||||
if (f[6] & 0x20) != 0x00 {
|
|
||||||
e.FDF = true
|
|
||||||
}
|
|
||||||
|
|
||||||
e.BRS = false
|
|
||||||
if (f[6] & 0x10) != 0x00 {
|
|
||||||
e.BRS = true
|
|
||||||
}
|
|
||||||
|
|
||||||
e.DLC = f[6] & 0x0F
|
|
||||||
|
|
||||||
e.RXTS = (uint16(f[5]) << 8) + uint16(f[4])
|
|
||||||
|
|
||||||
for i := byte(0); i < CANDlcToLength(e.DLC, e.FDF); i++ {
|
|
||||||
e.DB[i] = f[i+8]
|
|
||||||
}
|
|
||||||
|
|
||||||
can.Bus.RXF0A.ReplaceBits(idx, sam.CAN_RXF0A_F0AI_Msk, sam.CAN_RXF0A_F0AI_Pos)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rx receives a CAN frame. It is easier to use than RxRaw, but not as
|
|
||||||
// flexible.
|
|
||||||
func (can *CAN) Rx() (id uint32, dlc byte, data []byte, isFd, isExtendedID bool) {
|
|
||||||
e := CANRxBufferElement{}
|
|
||||||
can.RxRaw(&e)
|
|
||||||
length := CANDlcToLength(e.DLC, e.FDF)
|
|
||||||
return e.ID, length, e.DB[:length], e.FDF, e.XTD
|
|
||||||
}
|
|
||||||
|
|
||||||
func (can *CAN) instance() byte {
|
|
||||||
if can.Bus == sam.CAN0 {
|
|
||||||
return 0
|
|
||||||
} else {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CANTxBufferElement is a struct that corresponds to the same5x' Tx Buffer
|
|
||||||
// Element.
|
|
||||||
type CANTxBufferElement struct {
|
|
||||||
ESI bool
|
|
||||||
XTD bool
|
|
||||||
RTR bool
|
|
||||||
ID uint32
|
|
||||||
MM uint8
|
|
||||||
EFC bool
|
|
||||||
FDF bool
|
|
||||||
BRS bool
|
|
||||||
DLC uint8
|
|
||||||
DB [64]uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// CANRxBufferElement is a struct that corresponds to the same5x Rx Buffer and
|
|
||||||
// FIFO Element.
|
|
||||||
type CANRxBufferElement struct {
|
|
||||||
ESI bool
|
|
||||||
XTD bool
|
|
||||||
RTR bool
|
|
||||||
ID uint32
|
|
||||||
ANMF bool
|
|
||||||
FIDX uint8
|
|
||||||
FDF bool
|
|
||||||
BRS bool
|
|
||||||
DLC uint8
|
|
||||||
RXTS uint16
|
|
||||||
DB [64]uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data returns the received data as a slice of the size according to dlc.
|
|
||||||
func (e CANRxBufferElement) Data() []byte {
|
|
||||||
return e.DB[:CANDlcToLength(e.DLC, e.FDF)]
|
|
||||||
}
|
|
||||||
|
|
||||||
// CANDlcToLength() converts a DLC value to its actual length.
|
|
||||||
func CANDlcToLength(dlc byte, isFD bool) byte {
|
|
||||||
length := dlc
|
|
||||||
if dlc == 0x09 {
|
|
||||||
length = 12
|
|
||||||
} else if dlc == 0x0A {
|
|
||||||
length = 16
|
|
||||||
} else if dlc == 0x0B {
|
|
||||||
length = 20
|
|
||||||
} else if dlc == 0x0C {
|
|
||||||
length = 24
|
|
||||||
} else if dlc == 0x0D {
|
|
||||||
length = 32
|
|
||||||
} else if dlc == 0x0E {
|
|
||||||
length = 48
|
|
||||||
} else if dlc == 0x0F {
|
|
||||||
length = 64
|
|
||||||
}
|
|
||||||
return length
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// CANLengthToDlc() converts its actual length to a DLC value.
|
|
||||||
func CANLengthToDlc(length byte, isFD bool) byte {
|
|
||||||
dlc := length
|
|
||||||
if length <= 0x08 {
|
|
||||||
} else if length <= 12 {
|
|
||||||
dlc = 0x09
|
|
||||||
} else if length <= 16 {
|
|
||||||
dlc = 0x0A
|
|
||||||
} else if length <= 20 {
|
|
||||||
dlc = 0x0B
|
|
||||||
} else if length <= 24 {
|
|
||||||
dlc = 0x0C
|
|
||||||
} else if length <= 32 {
|
|
||||||
dlc = 0x0D
|
|
||||||
} else if length <= 48 {
|
|
||||||
dlc = 0x0E
|
|
||||||
} else if length <= 64 {
|
|
||||||
dlc = 0x0F
|
|
||||||
}
|
|
||||||
return dlc
|
|
||||||
}
|
|
||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PinInput PinMode = iota
|
PinInput PinMode = iota
|
||||||
PinInputPullup
|
PinInputPullup
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ var (
|
|||||||
ErrInvalidSPIBus = errors.New("machine: invalid SPI bus")
|
ErrInvalidSPIBus = errors.New("machine: invalid SPI bus")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PinOutput PinMode = iota
|
PinOutput PinMode = iota
|
||||||
PinInput
|
PinInput
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ func CPUFrequency() uint32 {
|
|||||||
return 80000000 // 80MHz
|
return 80000000 // 80MHz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PinOutput PinMode = iota
|
PinOutput PinMode = iota
|
||||||
PinInput
|
PinInput
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ func CPUFrequency() uint32 {
|
|||||||
return 16000000
|
return 16000000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PinInput PinMode = iota
|
PinInput PinMode = iota
|
||||||
PinOutput
|
PinOutput
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ const (
|
|||||||
// Make it easier to directly write to I/O RAM.
|
// Make it easier to directly write to I/O RAM.
|
||||||
var ioram = (*[0x400]volatile.Register8)(unsafe.Pointer(uintptr(0x04000000)))
|
var ioram = (*[0x400]volatile.Register8)(unsafe.Pointer(uintptr(0x04000000)))
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
// Set has not been implemented.
|
// Set has not been implemented.
|
||||||
func (p Pin) Set(value bool) {
|
func (p Pin) Set(value bool) {
|
||||||
// do nothing
|
// do nothing
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ var (
|
|||||||
UART0 = UART{0}
|
UART0 = UART{0}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PinInput PinMode = iota
|
PinInput PinMode = iota
|
||||||
PinOutput
|
PinOutput
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ func CPUFrequency() uint32 {
|
|||||||
return 390000000
|
return 390000000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
type fpioaPullMode uint8
|
type fpioaPullMode uint8
|
||||||
type PinChange uint8
|
type PinChange uint8
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ func CPUFrequency() uint32 {
|
|||||||
return 600000000
|
return 600000000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// GPIO
|
// GPIO
|
||||||
PinInput PinMode = iota
|
PinInput PinMode = iota
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ var (
|
|||||||
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
|
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PinInput PinMode = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos)
|
PinInput PinMode = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos)
|
||||||
PinInputPullup PinMode = PinInput | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos)
|
PinInputPullup PinMode = PinInput | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos)
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PinInput PinMode = iota
|
PinInput PinMode = iota
|
||||||
PinInputPullUp
|
PinInputPullUp
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ const (
|
|||||||
portJ
|
portJ
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type PinMode uint8
|
||||||
|
|
||||||
// Peripheral operations sequence:
|
// Peripheral operations sequence:
|
||||||
// 1. Enable the clock to the alternate function.
|
// 1. Enable the clock to the alternate function.
|
||||||
// 2. Enable clock to corresponding GPIO
|
// 2. Enable clock to corresponding GPIO
|
||||||
|
|||||||
@@ -204,16 +204,15 @@ func (spi SPI) configurePins(config SPIConfig) {
|
|||||||
// There are 2 I2C interfaces on the STM32F103xx.
|
// There are 2 I2C interfaces on the STM32F103xx.
|
||||||
// Since the first interface is named I2C1, both I2C0 and I2C1 refer to I2C1.
|
// Since the first interface is named I2C1, both I2C0 and I2C1 refer to I2C1.
|
||||||
// TODO: implement I2C2.
|
// TODO: implement I2C2.
|
||||||
|
var (
|
||||||
|
I2C1 = (*I2C)(unsafe.Pointer(stm32.I2C1))
|
||||||
|
I2C0 = I2C1
|
||||||
|
)
|
||||||
|
|
||||||
type I2C struct {
|
type I2C struct {
|
||||||
Bus *stm32.I2C_Type
|
Bus *stm32.I2C_Type
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
I2C1 = &I2C{Bus: stm32.I2C1}
|
|
||||||
I2C0 = I2C1
|
|
||||||
)
|
|
||||||
|
|
||||||
func (i2c *I2C) configurePins(config I2CConfig) {
|
func (i2c *I2C) configurePins(config I2CConfig) {
|
||||||
if config.SDA == PB9 {
|
if config.SDA == PB9 {
|
||||||
// use alternate I2C1 pins PB8/PB9 via AFIO mapping
|
// use alternate I2C1 pins PB8/PB9 via AFIO mapping
|
||||||
|
|||||||
@@ -14,9 +14,6 @@ const TargetBits = 32
|
|||||||
//go:extern __heap_base
|
//go:extern __heap_base
|
||||||
var heapStartSymbol [0]byte
|
var heapStartSymbol [0]byte
|
||||||
|
|
||||||
//go:extern __global_base
|
|
||||||
var globalsStartSymbol [0]byte
|
|
||||||
|
|
||||||
//export llvm.wasm.memory.size.i32
|
//export llvm.wasm.memory.size.i32
|
||||||
func wasm_memory_size(index int32) int32
|
func wasm_memory_size(index int32) int32
|
||||||
|
|
||||||
@@ -24,10 +21,8 @@ func wasm_memory_size(index int32) int32
|
|||||||
func wasm_memory_grow(index int32, delta int32) int32
|
func wasm_memory_grow(index int32, delta int32) int32
|
||||||
|
|
||||||
var (
|
var (
|
||||||
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
|
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
|
||||||
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
|
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
|
||||||
globalsStart = uintptr(unsafe.Pointer(&globalsStartSymbol))
|
|
||||||
globalsEnd = uintptr(unsafe.Pointer(&heapStartSymbol))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const wasmPageSize = 64 * 1024
|
const wasmPageSize = 64 * 1024
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ func markRoots(start, end uintptr) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for addr := start; addr < end; addr += unsafe.Alignof(addr) {
|
for addr := start; addr != end; addr += unsafe.Alignof(addr) {
|
||||||
root := *(*uintptr)(unsafe.Pointer(addr))
|
root := *(*uintptr)(unsafe.Pointer(addr))
|
||||||
markRoot(addr, root)
|
markRoot(addr, root)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// +build gc.conservative gc.extalloc
|
// +build gc.conservative gc.extalloc
|
||||||
// +build baremetal wasm
|
// +build baremetal
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// +build gc.conservative gc.extalloc
|
// +build gc.conservative gc.extalloc
|
||||||
// +build !baremetal,!wasm
|
// +build !baremetal
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,3 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
const GOOS = "darwin"
|
const GOOS = "darwin"
|
||||||
|
|
||||||
const (
|
|
||||||
// See https://github.com/golang/go/blob/master/src/syscall/zerrors_darwin_amd64.go
|
|
||||||
flag_PROT_READ = 0x1
|
|
||||||
flag_PROT_WRITE = 0x2
|
|
||||||
flag_MAP_PRIVATE = 0x2
|
|
||||||
flag_MAP_ANONYMOUS = 0x1000 // MAP_ANON
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -3,11 +3,3 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
const GOOS = "linux"
|
const GOOS = "linux"
|
||||||
|
|
||||||
const (
|
|
||||||
// See https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/mman-common.h
|
|
||||||
flag_PROT_READ = 0x1
|
|
||||||
flag_PROT_WRITE = 0x2
|
|
||||||
flag_MAP_PRIVATE = 0x2
|
|
||||||
flag_MAP_ANONYMOUS = 0x20
|
|
||||||
)
|
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ func ticks() timeUnit {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func sleepTicks(d timeUnit) {
|
func sleepTicks(d timeUnit) {
|
||||||
// TODO
|
// TODO
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,19 +217,11 @@ func initRTC() {
|
|||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
rtcInterrupt := interrupt.New(sam.IRQ_RTC, func(intr interrupt.Interrupt) {
|
rtcInterrupt := interrupt.New(sam.IRQ_RTC, func(intr interrupt.Interrupt) {
|
||||||
flags := sam.RTC_MODE0.INTFLAG.Get()
|
// disable IRQ for CMP0 compare
|
||||||
if flags&sam.RTC_MODE0_INTENSET_CMP0 != 0 {
|
sam.RTC_MODE0.INTFLAG.Set(sam.RTC_MODE0_INTENSET_CMP0)
|
||||||
// The timer (for a sleep) has expired.
|
|
||||||
timerWakeup.Set(1)
|
timerWakeup.Set(1)
|
||||||
}
|
|
||||||
if flags&sam.RTC_MODE0_INTENSET_OVF != 0 {
|
|
||||||
// The 32-bit RTC timer has overflowed.
|
|
||||||
rtcOverflows.Set(rtcOverflows.Get() + 1)
|
|
||||||
}
|
|
||||||
// Mark this interrupt has handled for CMP0 and OVF.
|
|
||||||
sam.RTC_MODE0.INTFLAG.Set(sam.RTC_MODE0_INTENSET_CMP0 | sam.RTC_MODE0_INTENSET_OVF)
|
|
||||||
})
|
})
|
||||||
sam.RTC_MODE0.INTENSET.Set(sam.RTC_MODE0_INTENSET_OVF)
|
|
||||||
rtcInterrupt.SetPriority(0xc0)
|
rtcInterrupt.SetPriority(0xc0)
|
||||||
rtcInterrupt.Enable()
|
rtcInterrupt.Enable()
|
||||||
}
|
}
|
||||||
@@ -239,10 +231,15 @@ func waitForSync() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var rtcOverflows volatile.Register32 // number of times the RTC wrapped around
|
var (
|
||||||
|
timestamp timeUnit // ticks since boottime
|
||||||
|
timerLastCounter uint64
|
||||||
|
)
|
||||||
|
|
||||||
var timerWakeup volatile.Register8
|
var timerWakeup volatile.Register8
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
|
// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
// The following calculation is actually the following, but with both sides
|
// The following calculation is actually the following, but with both sides
|
||||||
@@ -262,6 +259,7 @@ func nanosecondsToTicks(ns int64) timeUnit {
|
|||||||
// sleepTicks should sleep for d number of microseconds.
|
// sleepTicks should sleep for d number of microseconds.
|
||||||
func sleepTicks(d timeUnit) {
|
func sleepTicks(d timeUnit) {
|
||||||
for d != 0 {
|
for d != 0 {
|
||||||
|
ticks() // update timestamp
|
||||||
ticks := uint32(d)
|
ticks := uint32(d)
|
||||||
if !timerSleep(ticks) {
|
if !timerSleep(ticks) {
|
||||||
// Bail out early to handle a non-time interrupt.
|
// Bail out early to handle a non-time interrupt.
|
||||||
@@ -271,37 +269,17 @@ func sleepTicks(d timeUnit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ticks returns the elapsed time since reset.
|
// ticks returns number of microseconds since start.
|
||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
// For some ways of capturing the time atomically, see this thread:
|
|
||||||
// https://www.eevblog.com/forum/microcontrollers/correct-timing-by-timer-overflow-count/msg749617/#msg749617
|
|
||||||
// Here, instead of re-reading the counter register if an overflow has been
|
|
||||||
// detected, we simply try again because that results in smaller code.
|
|
||||||
for {
|
|
||||||
mask := interrupt.Disable()
|
|
||||||
counter := readRTC()
|
|
||||||
overflows := rtcOverflows.Get()
|
|
||||||
hasOverflow := sam.RTC_MODE0.INTFLAG.Get()&sam.RTC_MODE0_INTENSET_OVF != 0
|
|
||||||
interrupt.Restore(mask)
|
|
||||||
|
|
||||||
if hasOverflow {
|
|
||||||
// There was an overflow while trying to capture the timer.
|
|
||||||
// Try again.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a 32-bit timer, so the number of timer overflows forms the
|
|
||||||
// upper 32 bits of this timer.
|
|
||||||
return timeUnit(overflows)<<32 + timeUnit(counter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func readRTC() uint32 {
|
|
||||||
// request read of count
|
// request read of count
|
||||||
sam.RTC_MODE0.READREQ.Set(sam.RTC_MODE0_READREQ_RREQ)
|
sam.RTC_MODE0.READREQ.Set(sam.RTC_MODE0_READREQ_RREQ)
|
||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
return sam.RTC_MODE0.COUNT.Get()
|
rtcCounter := uint64(sam.RTC_MODE0.COUNT.Get()) // each counter tick == 30.5us
|
||||||
|
offset := (rtcCounter - timerLastCounter) // change since last measurement
|
||||||
|
timerLastCounter = rtcCounter
|
||||||
|
timestamp += timeUnit(offset)
|
||||||
|
return timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
// ticks are in microseconds
|
// ticks are in microseconds
|
||||||
@@ -327,7 +305,7 @@ func timerSleep(ticks uint32) bool {
|
|||||||
waitForSync()
|
waitForSync()
|
||||||
|
|
||||||
// enable IRQ for CMP0 compare
|
// enable IRQ for CMP0 compare
|
||||||
sam.RTC_MODE0.INTENSET.Set(sam.RTC_MODE0_INTENSET_CMP0)
|
sam.RTC_MODE0.INTENSET.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
|
||||||
|
|
||||||
wait:
|
wait:
|
||||||
waitForEvents()
|
waitForEvents()
|
||||||
@@ -337,7 +315,7 @@ wait:
|
|||||||
if hasScheduler {
|
if hasScheduler {
|
||||||
// The interurpt may have awoken a goroutine, so bail out early.
|
// The interurpt may have awoken a goroutine, so bail out early.
|
||||||
// Disable IRQ for CMP0 compare.
|
// Disable IRQ for CMP0 compare.
|
||||||
sam.RTC_MODE0.INTENCLR.Set(sam.RTC_MODE0_INTENSET_CMP0)
|
sam.RTC_MODE0.INTENCLR.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
// This is running without a scheduler.
|
// This is running without a scheduler.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// +build sam,atsamd51 sam,atsame5x
|
// +build sam,atsamd51
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
@@ -16,7 +16,6 @@ func postinit() {}
|
|||||||
|
|
||||||
//export Reset_Handler
|
//export Reset_Handler
|
||||||
func main() {
|
func main() {
|
||||||
arm.SCB.CPACR.Set(0) // disable FPU if it is enabled
|
|
||||||
preinit()
|
preinit()
|
||||||
run()
|
run()
|
||||||
abort()
|
abort()
|
||||||
@@ -206,19 +205,11 @@ func initRTC() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
irq := interrupt.New(sam.IRQ_RTC, func(interrupt.Interrupt) {
|
irq := interrupt.New(sam.IRQ_RTC, func(interrupt.Interrupt) {
|
||||||
flags := sam.RTC_MODE0.INTFLAG.Get()
|
// disable IRQ for CMP0 compare
|
||||||
if flags&sam.RTC_MODE0_INTENSET_CMP0 != 0 {
|
sam.RTC_MODE0.INTFLAG.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
|
||||||
// The timer (for a sleep) has expired.
|
|
||||||
timerWakeup.Set(1)
|
timerWakeup.Set(1)
|
||||||
}
|
|
||||||
if flags&sam.RTC_MODE0_INTENSET_OVF != 0 {
|
|
||||||
// The 32-bit RTC timer has overflowed.
|
|
||||||
rtcOverflows.Set(rtcOverflows.Get() + 1)
|
|
||||||
}
|
|
||||||
// Mark this interrupt has handled for CMP0 and OVF.
|
|
||||||
sam.RTC_MODE0.INTFLAG.Set(sam.RTC_MODE0_INTENSET_CMP0 | sam.RTC_MODE0_INTENSET_OVF)
|
|
||||||
})
|
})
|
||||||
sam.RTC_MODE0.INTENSET.Set(sam.RTC_MODE0_INTENSET_OVF)
|
|
||||||
irq.SetPriority(0xc0)
|
irq.SetPriority(0xc0)
|
||||||
irq.Enable()
|
irq.Enable()
|
||||||
}
|
}
|
||||||
@@ -228,10 +219,15 @@ func waitForSync() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var rtcOverflows volatile.Register32 // number of times the RTC wrapped around
|
var (
|
||||||
|
timestamp timeUnit // ticks since boottime
|
||||||
|
timerLastCounter uint64
|
||||||
|
)
|
||||||
|
|
||||||
var timerWakeup volatile.Register8
|
var timerWakeup volatile.Register8
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
|
// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
// The following calculation is actually the following, but with both sides
|
// The following calculation is actually the following, but with both sides
|
||||||
@@ -251,6 +247,7 @@ func nanosecondsToTicks(ns int64) timeUnit {
|
|||||||
// sleepTicks should sleep for d number of microseconds.
|
// sleepTicks should sleep for d number of microseconds.
|
||||||
func sleepTicks(d timeUnit) {
|
func sleepTicks(d timeUnit) {
|
||||||
for d != 0 {
|
for d != 0 {
|
||||||
|
ticks() // update timestamp
|
||||||
ticks := uint32(d)
|
ticks := uint32(d)
|
||||||
if !timerSleep(ticks) {
|
if !timerSleep(ticks) {
|
||||||
return
|
return
|
||||||
@@ -259,34 +256,15 @@ func sleepTicks(d timeUnit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ticks returns the elapsed time since reset.
|
// ticks returns number of microseconds since start.
|
||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
// For some ways of capturing the time atomically, see this thread:
|
|
||||||
// https://www.eevblog.com/forum/microcontrollers/correct-timing-by-timer-overflow-count/msg749617/#msg749617
|
|
||||||
// Here, instead of re-reading the counter register if an overflow has been
|
|
||||||
// detected, we simply try again because that results in smaller code.
|
|
||||||
for {
|
|
||||||
mask := interrupt.Disable()
|
|
||||||
counter := readRTC()
|
|
||||||
overflows := rtcOverflows.Get()
|
|
||||||
hasOverflow := sam.RTC_MODE0.INTFLAG.Get()&sam.RTC_MODE0_INTENSET_OVF != 0
|
|
||||||
interrupt.Restore(mask)
|
|
||||||
|
|
||||||
if hasOverflow {
|
|
||||||
// There was an overflow while trying to capture the timer.
|
|
||||||
// Try again.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is a 32-bit timer, so the number of timer overflows forms the
|
|
||||||
// upper 32 bits of this timer.
|
|
||||||
return timeUnit(overflows)<<32 + timeUnit(counter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func readRTC() uint32 {
|
|
||||||
waitForSync()
|
waitForSync()
|
||||||
return sam.RTC_MODE0.COUNT.Get()
|
|
||||||
|
rtcCounter := uint64(sam.RTC_MODE0.COUNT.Get())
|
||||||
|
offset := (rtcCounter - timerLastCounter) // change since last measurement
|
||||||
|
timerLastCounter = rtcCounter
|
||||||
|
timestamp += timeUnit(offset)
|
||||||
|
return timestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
// ticks are in microseconds
|
// ticks are in microseconds
|
||||||
@@ -311,7 +289,7 @@ func timerSleep(ticks uint32) bool {
|
|||||||
sam.RTC_MODE0.COMP[0].Set(uint32(cnt) + ticks)
|
sam.RTC_MODE0.COMP[0].Set(uint32(cnt) + ticks)
|
||||||
|
|
||||||
// enable IRQ for CMP0 compare
|
// enable IRQ for CMP0 compare
|
||||||
sam.RTC_MODE0.INTENSET.Set(sam.RTC_MODE0_INTENSET_CMP0)
|
sam.RTC_MODE0.INTENSET.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
|
||||||
|
|
||||||
wait:
|
wait:
|
||||||
waitForEvents()
|
waitForEvents()
|
||||||
@@ -321,7 +299,7 @@ wait:
|
|||||||
if hasScheduler {
|
if hasScheduler {
|
||||||
// The interurpt may have awoken a goroutine, so bail out early.
|
// The interurpt may have awoken a goroutine, so bail out early.
|
||||||
// Disable IRQ for CMP0 compare.
|
// Disable IRQ for CMP0 compare.
|
||||||
sam.RTC_MODE0.INTENCLR.Set(sam.RTC_MODE0_INTENSET_CMP0)
|
sam.RTC_MODE0.INTENCLR.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
|
||||||
return false
|
return false
|
||||||
} else {
|
} else {
|
||||||
// This is running without a scheduler.
|
// This is running without a scheduler.
|
||||||
|
|||||||
@@ -0,0 +1,338 @@
|
|||||||
|
// +build sam,atsame5x
|
||||||
|
|
||||||
|
package runtime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/arm"
|
||||||
|
"device/sam"
|
||||||
|
"machine"
|
||||||
|
"runtime/interrupt"
|
||||||
|
"runtime/volatile"
|
||||||
|
)
|
||||||
|
|
||||||
|
type timeUnit int64
|
||||||
|
|
||||||
|
func postinit() {}
|
||||||
|
|
||||||
|
//export Reset_Handler
|
||||||
|
func main() {
|
||||||
|
preinit()
|
||||||
|
run()
|
||||||
|
abort()
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
initClocks()
|
||||||
|
initRTC()
|
||||||
|
initSERCOMClocks()
|
||||||
|
initUSBClock()
|
||||||
|
initADCClock()
|
||||||
|
|
||||||
|
// connect to USB CDC interface
|
||||||
|
machine.UART0.Configure(machine.UARTConfig{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func putchar(c byte) {
|
||||||
|
machine.UART0.WriteByte(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initClocks() {
|
||||||
|
// set flash wait state
|
||||||
|
sam.NVMCTRL.CTRLA.SetBits(0 << sam.NVMCTRL_CTRLA_RWS_Pos)
|
||||||
|
|
||||||
|
// software reset
|
||||||
|
sam.GCLK.CTRLA.SetBits(sam.GCLK_CTRLA_SWRST)
|
||||||
|
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_SWRST) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set OSCULP32K as source of Generic Clock Generator 3
|
||||||
|
// GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_XOSC32K].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_OSCULP32K) | GCLK_GENCTRL_GENEN; //generic clock gen 3
|
||||||
|
sam.GCLK.GENCTRL[3].Set((sam.GCLK_GENCTRL_SRC_OSCULP32K << sam.GCLK_GENCTRL_SRC_Pos) |
|
||||||
|
sam.GCLK_GENCTRL_GENEN)
|
||||||
|
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK3) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set OSCULP32K as source of Generic Clock Generator 0
|
||||||
|
sam.GCLK.GENCTRL[0].Set((sam.GCLK_GENCTRL_SRC_OSCULP32K << sam.GCLK_GENCTRL_SRC_Pos) |
|
||||||
|
sam.GCLK_GENCTRL_GENEN)
|
||||||
|
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable DFLL48M clock
|
||||||
|
sam.OSCCTRL.DFLLCTRLA.Set(0)
|
||||||
|
sam.OSCCTRL.DFLLMUL.Set((0x1 << sam.OSCCTRL_DFLLMUL_CSTEP_Pos) |
|
||||||
|
(0x1 << sam.OSCCTRL_DFLLMUL_FSTEP_Pos) |
|
||||||
|
(0x0 << sam.OSCCTRL_DFLLMUL_MUL_Pos))
|
||||||
|
for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_DFLLMUL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
sam.OSCCTRL.DFLLCTRLB.Set(0)
|
||||||
|
for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_DFLLCTRLB) {
|
||||||
|
}
|
||||||
|
|
||||||
|
sam.OSCCTRL.DFLLCTRLA.SetBits(sam.OSCCTRL_DFLLCTRLA_ENABLE)
|
||||||
|
for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_ENABLE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
sam.OSCCTRL.DFLLVAL.Set(sam.OSCCTRL.DFLLVAL.Get())
|
||||||
|
for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_DFLLVAL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
sam.OSCCTRL.DFLLCTRLB.Set(sam.OSCCTRL_DFLLCTRLB_WAITLOCK |
|
||||||
|
sam.OSCCTRL_DFLLCTRLB_CCDIS |
|
||||||
|
sam.OSCCTRL_DFLLCTRLB_USBCRM)
|
||||||
|
for !sam.OSCCTRL.STATUS.HasBits(sam.OSCCTRL_STATUS_DFLLRDY) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// set GCLK7 to run at 2MHz, using DFLL48M as clock source
|
||||||
|
// GCLK7 = 48MHz / 24 = 2MHz
|
||||||
|
sam.GCLK.GENCTRL[7].Set((sam.GCLK_GENCTRL_SRC_DFLL << sam.GCLK_GENCTRL_SRC_Pos) |
|
||||||
|
(24 << sam.GCLK_GENCTRL_DIV_Pos) |
|
||||||
|
sam.GCLK_GENCTRL_GENEN)
|
||||||
|
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK7) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up the PLLs
|
||||||
|
|
||||||
|
// Set PLL0 to run at 120MHz, using GCLK7 as clock source
|
||||||
|
sam.GCLK.PCHCTRL[1].Set(sam.GCLK_PCHCTRL_CHEN |
|
||||||
|
(sam.GCLK_PCHCTRL_GEN_GCLK7 << sam.GCLK_PCHCTRL_GEN_Pos))
|
||||||
|
|
||||||
|
// multiplier = 59 + 1 + (0/32) = 60
|
||||||
|
// PLL0 = 2MHz * 60 = 120MHz
|
||||||
|
sam.OSCCTRL.DPLL[0].DPLLRATIO.Set((0x0 << sam.OSCCTRL_DPLL_DPLLRATIO_LDRFRAC_Pos) |
|
||||||
|
(59 << sam.OSCCTRL_DPLL_DPLLRATIO_LDR_Pos))
|
||||||
|
for sam.OSCCTRL.DPLL[0].DPLLSYNCBUSY.HasBits(sam.OSCCTRL_DPLL_DPLLSYNCBUSY_DPLLRATIO) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// MUST USE LBYPASS DUE TO BUG IN REV A OF SAMD51, via Adafruit lib.
|
||||||
|
sam.OSCCTRL.DPLL[0].DPLLCTRLB.Set((sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_GCLK << sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_Pos) |
|
||||||
|
sam.OSCCTRL_DPLL_DPLLCTRLB_LBYPASS)
|
||||||
|
|
||||||
|
sam.OSCCTRL.DPLL[0].DPLLCTRLA.Set(sam.OSCCTRL_DPLL_DPLLCTRLA_ENABLE)
|
||||||
|
for !sam.OSCCTRL.DPLL[0].DPLLSTATUS.HasBits(sam.OSCCTRL_DPLL_DPLLSTATUS_CLKRDY) ||
|
||||||
|
!sam.OSCCTRL.DPLL[0].DPLLSTATUS.HasBits(sam.OSCCTRL_DPLL_DPLLSTATUS_LOCK) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set PLL1 to run at 100MHz, using GCLK7 as clock source
|
||||||
|
sam.GCLK.PCHCTRL[2].Set(sam.GCLK_PCHCTRL_CHEN |
|
||||||
|
(sam.GCLK_PCHCTRL_GEN_GCLK7 << sam.GCLK_PCHCTRL_GEN_Pos))
|
||||||
|
|
||||||
|
// multiplier = 49 + 1 + (0/32) = 50
|
||||||
|
// PLL1 = 2MHz * 50 = 100MHz
|
||||||
|
sam.OSCCTRL.DPLL[1].DPLLRATIO.Set((0x0 << sam.OSCCTRL_DPLL_DPLLRATIO_LDRFRAC_Pos) |
|
||||||
|
(49 << sam.OSCCTRL_DPLL_DPLLRATIO_LDR_Pos))
|
||||||
|
for sam.OSCCTRL.DPLL[1].DPLLSYNCBUSY.HasBits(sam.OSCCTRL_DPLL_DPLLSYNCBUSY_DPLLRATIO) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// // MUST USE LBYPASS DUE TO BUG IN REV A OF SAMD51
|
||||||
|
sam.OSCCTRL.DPLL[1].DPLLCTRLB.Set((sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_GCLK << sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_Pos) |
|
||||||
|
sam.OSCCTRL_DPLL_DPLLCTRLB_LBYPASS)
|
||||||
|
|
||||||
|
sam.OSCCTRL.DPLL[1].DPLLCTRLA.Set(sam.OSCCTRL_DPLL_DPLLCTRLA_ENABLE)
|
||||||
|
// for !sam.OSCCTRL.DPLLSTATUS1.HasBits(sam.OSCCTRL_DPLLSTATUS_CLKRDY) ||
|
||||||
|
// !sam.OSCCTRL.DPLLSTATUS1.HasBits(sam.OSCCTRL_DPLLSTATUS_LOCK) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Set up the peripheral clocks
|
||||||
|
// Set 48MHZ CLOCK FOR USB
|
||||||
|
sam.GCLK.GENCTRL[1].Set((sam.GCLK_GENCTRL_SRC_DFLL << sam.GCLK_GENCTRL_SRC_Pos) |
|
||||||
|
sam.GCLK_GENCTRL_IDC |
|
||||||
|
sam.GCLK_GENCTRL_GENEN)
|
||||||
|
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK1) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Set 100MHZ CLOCK FOR OTHER PERIPHERALS
|
||||||
|
// sam.GCLK.GENCTRL2.Set((sam.GCLK_GENCTRL_SRC_DPLL1 << sam.GCLK_GENCTRL_SRC_Pos) |
|
||||||
|
// sam.GCLK_GENCTRL_IDC |
|
||||||
|
// sam.GCLK_GENCTRL_GENEN)
|
||||||
|
// for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL2) {
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Set 12MHZ CLOCK FOR DAC
|
||||||
|
sam.GCLK.GENCTRL[4].Set((sam.GCLK_GENCTRL_SRC_DFLL << sam.GCLK_GENCTRL_SRC_Pos) |
|
||||||
|
sam.GCLK_GENCTRL_IDC |
|
||||||
|
(4 << sam.GCLK_GENCTRL_DIVSEL_Pos) |
|
||||||
|
sam.GCLK_GENCTRL_GENEN)
|
||||||
|
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK4) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Set up main clock
|
||||||
|
sam.GCLK.GENCTRL[0].Set((sam.GCLK_GENCTRL_SRC_DPLL0 << sam.GCLK_GENCTRL_SRC_Pos) |
|
||||||
|
sam.GCLK_GENCTRL_IDC |
|
||||||
|
sam.GCLK_GENCTRL_GENEN)
|
||||||
|
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
sam.MCLK.CPUDIV.Set(sam.MCLK_CPUDIV_DIV_DIV1)
|
||||||
|
|
||||||
|
// Use the LDO regulator by default
|
||||||
|
sam.SUPC.VREG.ClearBits(sam.SUPC_VREG_SEL)
|
||||||
|
|
||||||
|
// Start up the "Debug Watchpoint and Trace" unit, so that we can use
|
||||||
|
// it's 32bit cycle counter for timing.
|
||||||
|
//CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
|
||||||
|
//DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
|
||||||
|
}
|
||||||
|
|
||||||
|
func initRTC() {
|
||||||
|
// turn on digital interface clock
|
||||||
|
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_RTC_)
|
||||||
|
|
||||||
|
// disable RTC
|
||||||
|
sam.RTC_MODE0.CTRLA.ClearBits(sam.RTC_MODE0_CTRLA_ENABLE)
|
||||||
|
//sam.RTC_MODE0.CTRLA.Set(0)
|
||||||
|
for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_ENABLE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset RTC
|
||||||
|
sam.RTC_MODE0.CTRLA.SetBits(sam.RTC_MODE0_CTRLA_SWRST)
|
||||||
|
for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_SWRST) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// set to use ulp 32k oscillator
|
||||||
|
sam.OSC32KCTRL.OSCULP32K.SetBits(sam.OSC32KCTRL_OSCULP32K_EN32K)
|
||||||
|
sam.OSC32KCTRL.RTCCTRL.Set(sam.OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K)
|
||||||
|
|
||||||
|
// set Mode0 to 32-bit counter (mode 0) with prescaler 1 and GCLK2 is 32KHz/1
|
||||||
|
sam.RTC_MODE0.CTRLA.Set((sam.RTC_MODE0_CTRLA_MODE_COUNT32 << sam.RTC_MODE0_CTRLA_MODE_Pos) |
|
||||||
|
(sam.RTC_MODE0_CTRLA_PRESCALER_DIV1 << sam.RTC_MODE0_CTRLA_PRESCALER_Pos) |
|
||||||
|
(sam.RTC_MODE0_CTRLA_COUNTSYNC))
|
||||||
|
|
||||||
|
// re-enable RTC
|
||||||
|
sam.RTC_MODE0.CTRLA.SetBits(sam.RTC_MODE0_CTRLA_ENABLE)
|
||||||
|
for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_ENABLE) {
|
||||||
|
}
|
||||||
|
|
||||||
|
irq := interrupt.New(sam.IRQ_RTC, func(interrupt.Interrupt) {
|
||||||
|
// disable IRQ for CMP0 compare
|
||||||
|
sam.RTC_MODE0.INTFLAG.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
|
||||||
|
|
||||||
|
timerWakeup.Set(1)
|
||||||
|
})
|
||||||
|
irq.SetPriority(0xc0)
|
||||||
|
irq.Enable()
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForSync() {
|
||||||
|
for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_COUNT) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
timestamp timeUnit // ticks since boottime
|
||||||
|
timerLastCounter uint64
|
||||||
|
)
|
||||||
|
|
||||||
|
var timerWakeup volatile.Register8
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
|
// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
|
||||||
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
|
// The following calculation is actually the following, but with both sides
|
||||||
|
// reduced to reduce the risk of overflow:
|
||||||
|
// ticks * 1e9 / 32768
|
||||||
|
return int64(ticks) * 1953125 / 64
|
||||||
|
}
|
||||||
|
|
||||||
|
// nanosecondsToTicks converts nanoseconds to RTC ticks (running at 32768Hz).
|
||||||
|
func nanosecondsToTicks(ns int64) timeUnit {
|
||||||
|
// The following calculation is actually the following, but with both sides
|
||||||
|
// reduced to reduce the risk of overflow:
|
||||||
|
// ns * 32768 / 1e9
|
||||||
|
return timeUnit(ns * 64 / 1953125)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sleepTicks should sleep for d number of microseconds.
|
||||||
|
func sleepTicks(d timeUnit) {
|
||||||
|
for d != 0 {
|
||||||
|
ticks() // update timestamp
|
||||||
|
ticks := uint32(d)
|
||||||
|
if !timerSleep(ticks) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
d -= timeUnit(ticks)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ticks returns number of microseconds since start.
|
||||||
|
func ticks() timeUnit {
|
||||||
|
waitForSync()
|
||||||
|
|
||||||
|
rtcCounter := uint64(sam.RTC_MODE0.COUNT.Get())
|
||||||
|
offset := (rtcCounter - timerLastCounter) // change since last measurement
|
||||||
|
timerLastCounter = rtcCounter
|
||||||
|
timestamp += timeUnit(offset)
|
||||||
|
return timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
// ticks are in microseconds
|
||||||
|
// Returns true if the timer completed.
|
||||||
|
// Returns false if another interrupt occured which requires an early return to scheduler.
|
||||||
|
func timerSleep(ticks uint32) bool {
|
||||||
|
timerWakeup.Set(0)
|
||||||
|
if ticks < 8 {
|
||||||
|
// due to delay waiting for the register value to sync, the minimum sleep value
|
||||||
|
// for the SAMD51 is 260us.
|
||||||
|
// For related info for SAMD21, see:
|
||||||
|
// https://community.atmel.com/comment/2507091#comment-2507091
|
||||||
|
ticks = 8
|
||||||
|
}
|
||||||
|
|
||||||
|
// request read of count
|
||||||
|
waitForSync()
|
||||||
|
|
||||||
|
// set compare value
|
||||||
|
cnt := sam.RTC_MODE0.COUNT.Get()
|
||||||
|
|
||||||
|
sam.RTC_MODE0.COMP[0].Set(uint32(cnt) + ticks)
|
||||||
|
|
||||||
|
// enable IRQ for CMP0 compare
|
||||||
|
sam.RTC_MODE0.INTENSET.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
|
||||||
|
|
||||||
|
wait:
|
||||||
|
waitForEvents()
|
||||||
|
if timerWakeup.Get() != 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if hasScheduler {
|
||||||
|
// The interurpt may have awoken a goroutine, so bail out early.
|
||||||
|
// Disable IRQ for CMP0 compare.
|
||||||
|
sam.RTC_MODE0.INTENCLR.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
// This is running without a scheduler.
|
||||||
|
// The application expects this to sleep the whole time.
|
||||||
|
goto wait
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func initUSBClock() {
|
||||||
|
// Turn on clock(s) for USB
|
||||||
|
//MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB;
|
||||||
|
//MCLK->AHBMASK.reg |= MCLK_AHBMASK_USB;
|
||||||
|
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_USB_)
|
||||||
|
sam.MCLK.AHBMASK.SetBits(sam.MCLK_AHBMASK_USB_)
|
||||||
|
|
||||||
|
// Put Generic Clock Generator 1 as source for USB
|
||||||
|
//GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
|
||||||
|
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_USB].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_PCHCTRL_CHEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
func initADCClock() {
|
||||||
|
// Turn on clocks for ADC0/ADC1.
|
||||||
|
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_ADC0_)
|
||||||
|
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_ADC1_)
|
||||||
|
|
||||||
|
// Put Generic Clock Generator 1 as source for ADC0 and ADC1.
|
||||||
|
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_ADC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_PCHCTRL_CHEN)
|
||||||
|
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_ADC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
|
||||||
|
sam.GCLK_PCHCTRL_CHEN)
|
||||||
|
}
|
||||||
|
|
||||||
|
func waitForEvents() {
|
||||||
|
arm.Asm("wfe")
|
||||||
|
}
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
// +build sam,atsame51 sam,atsame54
|
|
||||||
|
|
||||||
package runtime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"device/sam"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
initCANClock()
|
|
||||||
}
|
|
||||||
|
|
||||||
func initCANClock() {
|
|
||||||
// Turn on clocks for CAN0/CAN1.
|
|
||||||
sam.MCLK.AHBMASK.SetBits(sam.MCLK_AHBMASK_CAN0_)
|
|
||||||
sam.MCLK.AHBMASK.SetBits(sam.MCLK_AHBMASK_CAN1_)
|
|
||||||
|
|
||||||
// Put Generic Clock Generator 1 as source for USB
|
|
||||||
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_CAN0].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
|
|
||||||
sam.GCLK_PCHCTRL_CHEN)
|
|
||||||
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_CAN1].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
|
|
||||||
sam.GCLK_PCHCTRL_CHEN)
|
|
||||||
}
|
|
||||||
@@ -58,6 +58,8 @@ func init() {
|
|||||||
initUART()
|
initUART()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
const tickNanos = 1024 * 16384 // roughly 16ms in nanoseconds
|
const tickNanos = 1024 * 16384 // roughly 16ms in nanoseconds
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ func main() {
|
|||||||
abort()
|
abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
return int64(ticks)
|
return int64(ticks)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,6 +97,8 @@ func ticks() timeUnit {
|
|||||||
return timeUnit(uint64(esp.TIMG0.T0LO.Get()) | uint64(esp.TIMG0.T0HI.Get())<<32)
|
return timeUnit(uint64(esp.TIMG0.T0LO.Get()) | uint64(esp.TIMG0.T0HI.Get())<<32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func nanosecondsToTicks(ns int64) timeUnit {
|
func nanosecondsToTicks(ns int64) timeUnit {
|
||||||
// Calculate the number of ticks from the number of nanoseconds. At a 80MHz
|
// Calculate the number of ticks from the number of nanoseconds. At a 80MHz
|
||||||
// APB clock, that's 25 nanoseconds per tick with a timer prescaler of 2:
|
// APB clock, that's 25 nanoseconds per tick with a timer prescaler of 2:
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ func ticks() timeUnit {
|
|||||||
return currentTime
|
return currentTime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
const tickNanos = 3200 // time.Second / (80MHz / 256)
|
const tickNanos = 3200 // time.Second / (80MHz / 256)
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
|
|||||||
@@ -100,6 +100,8 @@ func putchar(c byte) {
|
|||||||
machine.UART0.WriteByte(c)
|
machine.UART0.WriteByte(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
var timerWakeup volatile.Register8
|
var timerWakeup volatile.Register8
|
||||||
|
|
||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
|
|||||||
@@ -112,6 +112,8 @@ func putchar(c byte) {
|
|||||||
machine.UART0.WriteByte(c)
|
machine.UART0.WriteByte(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
var timerWakeup volatile.Register8
|
var timerWakeup volatile.Register8
|
||||||
|
|
||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import (
|
|||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
//go:extern _svectors
|
//go:extern _svectors
|
||||||
var _svectors [0]byte
|
var _svectors [0]byte
|
||||||
|
|
||||||
@@ -100,6 +102,11 @@ func initSystem() {
|
|||||||
|
|
||||||
func initPeripherals() {
|
func initPeripherals() {
|
||||||
|
|
||||||
|
// enable FPU - set CP10, CP11 full access
|
||||||
|
nxp.SystemControl.CPACR.SetBits(
|
||||||
|
((nxp.SCB_CPACR_CP10_CP10_3 << nxp.SCB_CPACR_CP10_Pos) & nxp.SCB_CPACR_CP10_Msk) |
|
||||||
|
((nxp.SCB_CPACR_CP11_CP11_3 << nxp.SCB_CPACR_CP11_Pos) & nxp.SCB_CPACR_CP11_Msk))
|
||||||
|
|
||||||
enableTimerClocks() // activate GPT/PIT clock gates
|
enableTimerClocks() // activate GPT/PIT clock gates
|
||||||
initSysTick() // enable SysTick
|
initSysTick() // enable SysTick
|
||||||
initRTC() // enable real-time clock
|
initRTC() // enable real-time clock
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import "unsafe"
|
|||||||
|
|
||||||
type timeUnit int64
|
type timeUnit int64
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Handles
|
// Handles
|
||||||
infoTypeTotalMemorySize = 6 // Total amount of memory available for process.
|
infoTypeTotalMemorySize = 6 // Total amount of memory available for process.
|
||||||
|
|||||||
+19
-38
@@ -3,7 +3,6 @@
|
|||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"device/arm"
|
|
||||||
"device/nrf"
|
"device/nrf"
|
||||||
"machine"
|
"machine"
|
||||||
"runtime/interrupt"
|
"runtime/interrupt"
|
||||||
@@ -19,9 +18,6 @@ func postinit() {}
|
|||||||
|
|
||||||
//export Reset_Handler
|
//export Reset_Handler
|
||||||
func main() {
|
func main() {
|
||||||
if nrf.FPUPresent {
|
|
||||||
arm.SCB.CPACR.Set(0) // disable FPU if it is enabled
|
|
||||||
}
|
|
||||||
systemInit()
|
systemInit()
|
||||||
preinit()
|
preinit()
|
||||||
run()
|
run()
|
||||||
@@ -47,18 +43,10 @@ func initLFCLK() {
|
|||||||
func initRTC() {
|
func initRTC() {
|
||||||
nrf.RTC1.TASKS_START.Set(1)
|
nrf.RTC1.TASKS_START.Set(1)
|
||||||
intr := interrupt.New(nrf.IRQ_RTC1, func(intr interrupt.Interrupt) {
|
intr := interrupt.New(nrf.IRQ_RTC1, func(intr interrupt.Interrupt) {
|
||||||
if nrf.RTC1.EVENTS_COMPARE[0].Get() != 0 {
|
nrf.RTC1.INTENCLR.Set(nrf.RTC_INTENSET_COMPARE0)
|
||||||
nrf.RTC1.EVENTS_COMPARE[0].Set(0)
|
nrf.RTC1.EVENTS_COMPARE[0].Set(0)
|
||||||
nrf.RTC1.INTENCLR.Set(nrf.RTC_INTENSET_COMPARE0)
|
rtc_wakeup.Set(1)
|
||||||
nrf.RTC1.EVENTS_COMPARE[0].Set(0)
|
|
||||||
rtc_wakeup.Set(1)
|
|
||||||
}
|
|
||||||
if nrf.RTC1.EVENTS_OVRFLW.Get() != 0 {
|
|
||||||
nrf.RTC1.EVENTS_OVRFLW.Set(0)
|
|
||||||
rtcOverflows.Set(rtcOverflows.Get() + 1)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
nrf.RTC1.INTENSET.Set(nrf.RTC_INTENSET_OVRFLW)
|
|
||||||
intr.SetPriority(0xc0) // low priority
|
intr.SetPriority(0xc0) // low priority
|
||||||
intr.Enable()
|
intr.Enable()
|
||||||
}
|
}
|
||||||
@@ -67,15 +55,21 @@ func putchar(c byte) {
|
|||||||
machine.UART0.WriteByte(c)
|
machine.UART0.WriteByte(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func sleepTicks(d timeUnit) {
|
func sleepTicks(d timeUnit) {
|
||||||
for d != 0 {
|
for d != 0 {
|
||||||
|
ticks() // update timestamp
|
||||||
ticks := uint32(d) & 0x7fffff // 23 bits (to be on the safe side)
|
ticks := uint32(d) & 0x7fffff // 23 bits (to be on the safe side)
|
||||||
rtc_sleep(ticks)
|
rtc_sleep(ticks)
|
||||||
d -= timeUnit(ticks)
|
d -= timeUnit(ticks)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var rtcOverflows volatile.Register32 // number of times the RTC wrapped around
|
var (
|
||||||
|
timestamp timeUnit // nanoseconds since boottime
|
||||||
|
rtcLastCounter uint32 // 24 bits ticks
|
||||||
|
)
|
||||||
|
|
||||||
// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
|
// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
@@ -94,29 +88,16 @@ func nanosecondsToTicks(ns int64) timeUnit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Monotonically increasing numer of ticks since start.
|
// Monotonically increasing numer of ticks since start.
|
||||||
|
//
|
||||||
|
// Note: very long pauses between measurements (more than 8 minutes) may
|
||||||
|
// overflow the counter, leading to incorrect results. This might be fixed by
|
||||||
|
// handling the overflow event.
|
||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
// For some ways of capturing the time atomically, see this thread:
|
rtcCounter := uint32(nrf.RTC1.COUNTER.Get())
|
||||||
// https://www.eevblog.com/forum/microcontrollers/correct-timing-by-timer-overflow-count/msg749617/#msg749617
|
offset := (rtcCounter - rtcLastCounter) & 0xffffff // change since last measurement
|
||||||
// Here, instead of re-reading the counter register if an overflow has been
|
rtcLastCounter = rtcCounter
|
||||||
// detected, we simply try again because that results in (slightly) smaller
|
timestamp += timeUnit(offset)
|
||||||
// code and is perhaps easier to prove correct.
|
return timestamp
|
||||||
for {
|
|
||||||
mask := interrupt.Disable()
|
|
||||||
counter := uint32(nrf.RTC1.COUNTER.Get())
|
|
||||||
overflows := rtcOverflows.Get()
|
|
||||||
hasOverflow := nrf.RTC1.EVENTS_OVRFLW.Get() != 0
|
|
||||||
interrupt.Restore(mask)
|
|
||||||
|
|
||||||
if hasOverflow {
|
|
||||||
// There was an overflow. Try again.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// The counter is 24 bits in size, so the number of overflows form the
|
|
||||||
// upper 32 bits (together 56 bits, which covers 71493 years at
|
|
||||||
// 32768kHz: I'd argue good enough for most purposes).
|
|
||||||
return timeUnit(overflows)<<24 + timeUnit(counter)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var rtc_wakeup volatile.Register8
|
var rtc_wakeup volatile.Register8
|
||||||
|
|||||||
@@ -24,10 +24,10 @@ func waitForEvents() {
|
|||||||
if enabled != 0 {
|
if enabled != 0 {
|
||||||
// Now pick the appropriate SVCall number. Hopefully they won't change
|
// Now pick the appropriate SVCall number. Hopefully they won't change
|
||||||
// in the future with a different SoftDevice version.
|
// in the future with a different SoftDevice version.
|
||||||
if nrf.Device == "nrf51" {
|
if nrf.DEVICE == "nrf51" {
|
||||||
// sd_app_evt_wait: SOC_SVC_BASE_NOT_AVAILABLE + 29
|
// sd_app_evt_wait: SOC_SVC_BASE_NOT_AVAILABLE + 29
|
||||||
arm.SVCall0(0x2B + 29)
|
arm.SVCall0(0x2B + 29)
|
||||||
} else if nrf.Device == "nrf52" || nrf.Device == "nrf52840" || nrf.Device == "nrf52833" {
|
} else if nrf.DEVICE == "nrf52" || nrf.DEVICE == "nrf52840" || nrf.DEVICE == "nrf52833" {
|
||||||
// sd_app_evt_wait: SOC_SVC_BASE_NOT_AVAILABLE + 21
|
// sd_app_evt_wait: SOC_SVC_BASE_NOT_AVAILABLE + 21
|
||||||
arm.SVCall0(0x2C + 21)
|
arm.SVCall0(0x2C + 21)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -75,6 +75,7 @@ func initSystem() {
|
|||||||
nxp.SIM.SCGC3.Set(nxp.SIM_SCGC3_ADC1 | nxp.SIM_SCGC3_FTM2 | nxp.SIM_SCGC3_FTM3)
|
nxp.SIM.SCGC3.Set(nxp.SIM_SCGC3_ADC1 | nxp.SIM_SCGC3_FTM2 | nxp.SIM_SCGC3_FTM3)
|
||||||
nxp.SIM.SCGC5.Set(0x00043F82) // clocks active to all GPIO
|
nxp.SIM.SCGC5.Set(0x00043F82) // clocks active to all GPIO
|
||||||
nxp.SIM.SCGC6.Set(nxp.SIM_SCGC6_RTC | nxp.SIM_SCGC6_FTM0 | nxp.SIM_SCGC6_FTM1 | nxp.SIM_SCGC6_ADC0 | nxp.SIM_SCGC6_FTF)
|
nxp.SIM.SCGC6.Set(nxp.SIM_SCGC6_RTC | nxp.SIM_SCGC6_FTM0 | nxp.SIM_SCGC6_FTM1 | nxp.SIM_SCGC6_ADC0 | nxp.SIM_SCGC6_FTF)
|
||||||
|
nxp.SystemControl.CPACR.Set(0x00F00000)
|
||||||
nxp.LMEM.PCCCR.Set(0x85000003)
|
nxp.LMEM.PCCCR.Set(0x85000003)
|
||||||
|
|
||||||
// release I/O pins hold, if we woke up from VLLS mode
|
// release I/O pins hold, if we woke up from VLLS mode
|
||||||
@@ -232,6 +233,9 @@ func putchar(c byte) {
|
|||||||
machine.PutcharUART(&machine.UART0, c)
|
machine.PutcharUART(&machine.UART0, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ???
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func abort() {
|
func abort() {
|
||||||
println("!!! ABORT !!!")
|
println("!!! ABORT !!!")
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ const (
|
|||||||
|
|
||||||
type arrtype = uint32
|
type arrtype = uint32
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,8 @@ const (
|
|||||||
|
|
||||||
type arrtype = uint32
|
type arrtype = uint32
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initOSC() // configure oscillators
|
initOSC() // configure oscillators
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ const (
|
|||||||
|
|
||||||
type arrtype = uint32
|
type arrtype = uint32
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ const (
|
|||||||
|
|
||||||
type arrtype = uint32
|
type arrtype = uint32
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ const (
|
|||||||
|
|
||||||
type arrtype = uint16
|
type arrtype = uint16
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
machine.UART0.WriteByte(c)
|
machine.UART0.WriteByte(c)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,8 @@ const (
|
|||||||
|
|
||||||
type arrtype = uint32
|
type arrtype = uint32
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ const (
|
|||||||
|
|
||||||
type arrtype = uint32
|
type arrtype = uint32
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
initCLK()
|
initCLK()
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ func main() {
|
|||||||
abort()
|
abort()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
return int64(ticks)
|
return int64(ticks)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,6 @@ func usleep(usec uint) int
|
|||||||
//export malloc
|
//export malloc
|
||||||
func malloc(size uintptr) unsafe.Pointer
|
func malloc(size uintptr) unsafe.Pointer
|
||||||
|
|
||||||
//export mmap
|
|
||||||
func mmap(addr unsafe.Pointer, length, prot, flags, fd int, offset int) unsafe.Pointer
|
|
||||||
|
|
||||||
//export abort
|
//export abort
|
||||||
func abort()
|
func abort()
|
||||||
|
|
||||||
@@ -58,16 +55,18 @@ func main(argc int32, argv *unsafe.Pointer) int {
|
|||||||
cap uintptr
|
cap uintptr
|
||||||
})(unsafe.Pointer(&args))
|
})(unsafe.Pointer(&args))
|
||||||
argsSlice.ptr = malloc(uintptr(argc) * (unsafe.Sizeof(uintptr(0))) * 3)
|
argsSlice.ptr = malloc(uintptr(argc) * (unsafe.Sizeof(uintptr(0))) * 3)
|
||||||
argsSlice.len = uintptr(argc)
|
argsSlice.len = 0
|
||||||
argsSlice.cap = uintptr(argc)
|
argsSlice.cap = uintptr(argc)
|
||||||
|
|
||||||
// Initialize command line parameters.
|
// Initialize command line parameters.
|
||||||
for i := 0; i < int(argc); i++ {
|
for *argv != nil {
|
||||||
// Convert the C string to a Go string.
|
// Convert the C string to a Go string.
|
||||||
length := strlen(*argv)
|
length := strlen(*argv)
|
||||||
arg := (*_string)(unsafe.Pointer(&args[i]))
|
argString := _string{
|
||||||
arg.length = length
|
length: length,
|
||||||
arg.ptr = (*byte)(*argv)
|
ptr: (*byte)(*argv),
|
||||||
|
}
|
||||||
|
args = append(args, *(*string)(unsafe.Pointer(&argString)))
|
||||||
// This is the Go equivalent of "argc++" in C.
|
// This is the Go equivalent of "argc++" in C.
|
||||||
argv = (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + unsafe.Sizeof(argv)))
|
argv = (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + unsafe.Sizeof(argv)))
|
||||||
}
|
}
|
||||||
@@ -123,6 +122,8 @@ func putchar(c byte) {
|
|||||||
_putchar(int(c))
|
_putchar(int(c))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = false
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
// The OS API works in nanoseconds so no conversion necessary.
|
// The OS API works in nanoseconds so no conversion necessary.
|
||||||
return int64(ticks)
|
return int64(ticks)
|
||||||
|
|||||||
@@ -5,33 +5,20 @@
|
|||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
var heapSize uintptr = 128 * 1024 // small amount to start
|
const heapSize = 1 * 1024 * 1024 // 1MB to start
|
||||||
const heapMaxSize = 1 * 1024 * 1024 * 1024 // 1GB for the entire heap
|
|
||||||
|
|
||||||
var heapStart, heapEnd uintptr
|
var heapStart, heapEnd uintptr
|
||||||
|
|
||||||
func preinit() {
|
func preinit() {
|
||||||
// Allocate a large chunk of virtual memory. Because it is virtual, it won't
|
heapStart = uintptr(malloc(heapSize))
|
||||||
// really be allocated in RAM. Memory will only be allocated when it is
|
|
||||||
// first touched.
|
|
||||||
addr := mmap(nil, heapMaxSize, flag_PROT_READ|flag_PROT_WRITE, flag_MAP_PRIVATE|flag_MAP_ANONYMOUS, -1, 0)
|
|
||||||
heapStart = uintptr(addr)
|
|
||||||
heapEnd = heapStart + heapSize
|
heapEnd = heapStart + heapSize
|
||||||
}
|
}
|
||||||
|
|
||||||
// growHeap tries to grow the heap size. It returns true if it succeeds, false
|
// growHeap tries to grow the heap size. It returns true if it succeeds, false
|
||||||
// otherwise.
|
// otherwise.
|
||||||
func growHeap() bool {
|
func growHeap() bool {
|
||||||
if heapSize == heapMaxSize {
|
// At the moment, this is not possible. However it shouldn't be too
|
||||||
// Already at the max. If we run out of memory, we should consider
|
// difficult (at least on Linux) to allocate a large amount of virtual
|
||||||
// increasing heapMaxSize on 64-bit systems.
|
// memory at startup that is then slowly used.
|
||||||
return false
|
return false
|
||||||
}
|
|
||||||
// Grow the heap size used by the program.
|
|
||||||
heapSize = (heapSize * 4 / 3) &^ 4095 // grow by around 33%
|
|
||||||
if heapSize > heapMaxSize {
|
|
||||||
heapSize = heapMaxSize
|
|
||||||
}
|
|
||||||
setHeapEnd(heapStart + heapSize)
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ func go_scheduler() {
|
|||||||
scheduler()
|
scheduler()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const asyncScheduler = true
|
||||||
|
|
||||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||||
// The JavaScript API works in float64 milliseconds, so convert to
|
// The JavaScript API works in float64 milliseconds, so convert to
|
||||||
// nanoseconds first before converting to a timeUnit (which is a float64),
|
// nanoseconds first before converting to a timeUnit (which is a float64),
|
||||||
|
|||||||
@@ -30,9 +30,6 @@ func init() {
|
|||||||
// these args (argv).
|
// these args (argv).
|
||||||
var argc, argv_buf_size uint32
|
var argc, argv_buf_size uint32
|
||||||
args_sizes_get(&argc, &argv_buf_size)
|
args_sizes_get(&argc, &argv_buf_size)
|
||||||
if argc == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Obtain the command line arguments
|
// Obtain the command line arguments
|
||||||
argsSlice := make([]unsafe.Pointer, argc)
|
argsSlice := make([]unsafe.Pointer, argc)
|
||||||
@@ -59,7 +56,10 @@ func nanosecondsToTicks(ns int64) timeUnit {
|
|||||||
return timeUnit(ns)
|
return timeUnit(ns)
|
||||||
}
|
}
|
||||||
|
|
||||||
const timePrecisionNanoseconds = 1000 // TODO: how can we determine the appropriate `precision`?
|
const (
|
||||||
|
asyncScheduler = false
|
||||||
|
timePrecisionNanoseconds = 1000 // TODO: how can we determine the appropriate `precision`?
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
sleepTicksSubscription = __wasi_subscription_t{
|
sleepTicksSubscription = __wasi_subscription_t{
|
||||||
|
|||||||
@@ -20,10 +20,6 @@ import (
|
|||||||
|
|
||||||
const schedulerDebug = false
|
const schedulerDebug = false
|
||||||
|
|
||||||
// On JavaScript, we can't do a blocking sleep. Instead we have to return and
|
|
||||||
// queue a new scheduler invocation using setTimeout.
|
|
||||||
const asyncScheduler = GOOS == "js"
|
|
||||||
|
|
||||||
var schedulerDone bool
|
var schedulerDone bool
|
||||||
|
|
||||||
// Queues used by the scheduler.
|
// Queues used by the scheduler.
|
||||||
@@ -142,7 +138,6 @@ func scheduler() {
|
|||||||
if t == nil {
|
if t == nil {
|
||||||
if sleepQueue == nil {
|
if sleepQueue == nil {
|
||||||
if asyncScheduler {
|
if asyncScheduler {
|
||||||
// JavaScript is treated specially, see below.
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
waitForEvents()
|
waitForEvents()
|
||||||
@@ -159,8 +154,7 @@ func scheduler() {
|
|||||||
if asyncScheduler {
|
if asyncScheduler {
|
||||||
// The sleepTicks function above only sets a timeout at which
|
// The sleepTicks function above only sets a timeout at which
|
||||||
// point the scheduler will be called again. It does not really
|
// point the scheduler will be called again. It does not really
|
||||||
// sleep. So instead of sleeping, we return and expect to be
|
// sleep.
|
||||||
// called again.
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -201,10 +201,6 @@ type M struct {
|
|||||||
|
|
||||||
// Run the test suite.
|
// Run the test suite.
|
||||||
func (m *M) Run() int {
|
func (m *M) Run() int {
|
||||||
if len(m.Tests) == 0 {
|
|
||||||
fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
|
|
||||||
}
|
|
||||||
|
|
||||||
failures := 0
|
failures := 0
|
||||||
for _, test := range m.Tests {
|
for _, test := range m.Tests {
|
||||||
t := &T{
|
t := &T{
|
||||||
@@ -230,6 +226,7 @@ func (m *M) Run() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if failures > 0 {
|
if failures > 0 {
|
||||||
|
fmt.Printf("exit status %d\n", failures)
|
||||||
fmt.Println("FAIL")
|
fmt.Println("FAIL")
|
||||||
} else {
|
} else {
|
||||||
fmt.Println("PASS")
|
fmt.Println("PASS")
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"inherits": ["arduino-nano"],
|
|
||||||
"flash-command": "avrdude -c arduino -p atmega328p -b 115200 -P {port} -U flash:w:{hex}:i"
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,5 @@
|
|||||||
"inherits": ["atsame54p20a"],
|
"inherits": ["atsame54p20a"],
|
||||||
"build-tags": ["atsame54_xpro"],
|
"build-tags": ["atsame54_xpro"],
|
||||||
"flash-method": "openocd",
|
"flash-method": "openocd",
|
||||||
"openocd-interface": "cmsis-dap",
|
"openocd-interface": "cmsis-dap"
|
||||||
"default-stack-size": 4096
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"inherits": ["cortex-m4"],
|
"inherits": ["cortex-m4"],
|
||||||
"build-tags": ["sam", "atsame5x", "atsame54", "atsame54p20", "atsame54p20a"],
|
"build-tags": ["sam", "atsame5x", "atsame54p20", "atsame54p20a"],
|
||||||
"linkerscript": "targets/atsame5xx20-no-bootloader.ld",
|
"linkerscript": "targets/atsame5xx20-no-bootloader.ld",
|
||||||
"extra-files": [
|
"extra-files": [
|
||||||
"src/device/sam/atsame54p20a.s"
|
"src/device/sam/atsame54p20a.s"
|
||||||
|
|||||||
@@ -4,6 +4,5 @@
|
|||||||
"flash-1200-bps-reset": "true",
|
"flash-1200-bps-reset": "true",
|
||||||
"flash-method": "msd",
|
"flash-method": "msd",
|
||||||
"msd-volume-name": "FTHRCANBOOT",
|
"msd-volume-name": "FTHRCANBOOT",
|
||||||
"msd-firmware-name": "firmware.uf2",
|
"msd-firmware-name": "firmware.uf2"
|
||||||
"default-stack-size": 4096
|
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user