Compare commits

..

42 Commits

Author SHA1 Message Date
Ayke van Laethem da85710894 main: version 0.6.0 2019-05-29 16:38:04 +02:00
j7b 0ae467d3e2 llvm cpu features 2019-05-28 15:41:34 +02:00
Justin Clift 4442b1304e Trivial typo fix 2019-05-28 09:55:35 +02:00
Ayke van Laethem 83ab61e261 ci: install Go 1.12.5 on macOS
This should fix compatibility with the Go 1.12 stdlib:
https://github.com/tinygo-org/tinygo/issues/368
2019-05-27 19:47:12 +02:00
Ron Evans 2504754325 machine/samd21: use HasBits() method to simplify bit comparisons
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-27 18:43:11 +02:00
Ron Evans be491abc46 machine/stm32: use HasBits() method to simplify bit comparisons
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-27 18:43:11 +02:00
Ron Evans 31189deb3b machine/avr: use HasBits() method to simplify bit comparisons
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-27 18:43:11 +02:00
Ron Evans 90cd3f8ea5 tools: generate volatile HasBits() method in device wrappers to simplify bit comparison code
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-27 18:43:11 +02:00
Ayke van Laethem 2f95a5d452 ci: use go modules instead of dep
This also updates the LLVM build to include this commit:
https://github.com/llvm-mirror/llvm/commit/d519e424c503d2d2a723284664a509a6cd5401a8
2019-05-27 18:42:36 +02:00
Ayke van Laethem eb1d834dd4 wasm: add support for js.FuncOf 2019-05-27 13:35:59 +02:00
Ayke van Laethem 3313decb68 compiler,runtime: make panic functions camelCase
Rename panic functions to be runtime.nilPanic, runtime.lookupPanic, and
runtime.slicePanic.
2019-05-27 13:35:59 +02:00
Ron Evans 191a076956 docs: update list of supported MCU boards
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-27 09:43:24 +02:00
Ayke van Laethem 0f2dcba7b3 syscall: implement Exit call on unix 2019-05-27 07:50:13 +02:00
Ayke van Laethem 94b8214529 machine: refactor pins to be of Pin type 2019-05-26 20:48:50 +02:00
Ayke van Laethem 421ef04efb wasm: fix Makefile to avoid debuginfo 2019-05-25 18:40:56 +02:00
Ayke van Laethem f7687c43aa wasm: fix wasm-ld hang
See the following bugs for more information:
https://bugs.llvm.org/show_bug.cgi?id=41508
https://bugs.llvm.org/show_bug.cgi?id=37064
2019-05-25 18:25:46 +02:00
Ayke van Laethem 5a7bab8808 main: add the absolute path to clang-8 on macOS
This avoids the need to correctly set $PATH if LLVM 8 has been installed
using Homebrew.
2019-05-24 19:53:43 +02:00
Ron Evans 3a73e64557 tools/gen-device: complete refactor to new generator based on volatile package
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-24 16:28:47 +02:00
Ron Evans 9f8340a970 machine/nrf: refactor to use volatile package/API
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-24 15:44:33 +02:00
k-brk 0f6873cf02 machine/stm32f103xx: fix i2c 2 byte read 2019-05-24 15:26:06 +02:00
Ayke van Laethem f2cd4d12e8 compiler,runtime: fix multiple definitions of a single function
strings.IndexByte was implemented in the runtime up to Go 1.11. It is
implemented using a direct call to internal/bytealg.IndexByte since Go
1.12.

Make sure we remain compatible with both.
2019-05-24 14:51:40 +02:00
Ayke van Laethem 7e6a54ac62 main: add build tags for the Go stdlib version 2019-05-24 14:51:40 +02:00
Ayke van Laethem 7156afca9e interp: support some more expressions in const icmp 2019-05-24 14:00:23 +02:00
Ayke van Laethem 87ac804642 ci: make sure that all examples are included in the smoketests 2019-05-24 13:51:20 +02:00
Ayke van Laethem edcb11f9f6 ci: move tests from CircleCI config to Makefile
This makes it easier to run smoke tests locally.
2019-05-24 13:51:20 +02:00
Ayke van Laethem 3568254593 machine/atsamd21: fix analog pin mode 2019-05-23 20:37:10 +02:00
Ayke van Laethem 3bf4c06c99 interp: work around limitation of constfolding in IR builder
The IR builder does not appear to fold comparisons of constant inttoptr
instructions to const null pointer. So do it manually during
interpretatin, as a somewhat ugly hack.

This fixes https://github.com/tinygo-org/tinygo/issues/363
2019-05-21 19:33:19 +02:00
Ayke van Laethem f1d9e7b75e interp: make errors during branches more reliable
Previously, there was a suble error in that .IsConstant() is not always
allowed to be called, resulting in a i1 that was not 0 or 1. Fix this by
checking for the constants directly and adding some more diagnostics to
catch more cases.
2019-05-21 19:33:19 +02:00
Ron Evans e4d53daa02 machine/stm32: refactor to use new volatile package for all register access
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-21 15:08:43 +02:00
Ayke van Laethem 98a3047b58 all: add go.mod and go.sum files for vgo support
Add required files for vgo support. The new vgo system defaults to on
since Go 1.13 so we should be prepared for that once the release hits.
It is also useful for testing Go 1.13 before the release.
2019-05-20 11:40:29 +02:00
Ayke van Laethem ba85c82fbb arm: print an error when a HardFault occurs
This is very useful for debugging. It differentiates between a stack
overflow and other errors (because it's easy to see when a stack
overflow occurs) and prints the old stack pointer and program counter if
available.
2019-05-20 11:39:17 +02:00
Ayke van Laethem 7b6ef65fe7 compiler: create temporary allocas with appropriate lifetimes
Make sure all allocas are created in the entry block and are given the
right lifetimes. This is good for code quality:

  * Moving allocas to the entry block makes sure they are always
    allocated statically (avoiding the need for a frame pointer) and do
    not grow the stack on each new alloca instruction. This is
    especially useful in loops where it could otherwise lead to a stack
    overflow even though there is no recursion.
  * Adding lifetime markers allows LLVM to reuse stack areas for
    different allocas as long as their lifetimes do not overlap.

All in all, this reduces code size in all tested cases for the BBC
micro:bit, and reduces code size for most cases for WebAssembly.
2019-05-20 09:52:42 +02:00
Ron Evans de032cddd2 machine/sam: Refactor all machine/runtime code to use new volatile package/API
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-19 19:53:11 +02:00
Ron Evans 51c6b972bf machine/feather-m0: correct board build tag and add placeholders for I2S interface
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-19 19:52:14 +02:00
Anthony Elder 4cd151faf5 Add Feather M0 Board (#356)
* Add Feather M0 Board
2019-05-19 17:10:17 +02:00
Ayke van Laethem 5342d392aa interp: improve scan for loads
During a scan, consider loads from dirty globals to be dirty and check
whether they have any local side effects.

This fixes a problem with the new volatile operations that are now in
methods on registers instead of being emitted inline as volatile
instructions.
2019-05-18 18:30:22 +02:00
Ayke van Laethem f94af9f61e compiler: avoid some obviously false nil checks
Pointers to globals are never nil.
2019-05-18 18:30:22 +02:00
Ayke van Laethem 7ada00790c cgo: print better error messages for unknown types
Types used in a program may not be implemented. Print a nice error
message explaining the situation, instead of just prepending C. to the
type spelling (and hoping the user knows what that undefined reference
means).
2019-05-17 19:37:20 +02:00
Ayke van Laethem dfa713040a cgo: add support for enum types
Enum types are implemented as named types (with possible accompanying
typedefs as type aliases). The constants inside the enums are treated as
Go constants like in the Go toolchain.
2019-05-17 19:37:20 +02:00
Ron Evans 82dc14b741 docker: do not remove make from tinygo-dev docker image, to make it easier to run drivers CI build, which uses the tinygo-dev image
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-15 11:51:26 +02:00
Ron Evans d3f2237d44 docs: update README with new boards Adafruit Trinket M0, and STM32F407 Discovery
Signed-off-by: Ron Evans <ron@hybridgroup.com>
2019-05-14 19:38:39 +02:00
Martin Treml fc2ed2bdd0 [Board] Adafruit Trinket (#333)
* Add support for Adafruit Trinket-M0 board
2019-05-14 19:30:39 +02:00
104 changed files with 3453 additions and 2373 deletions
+17 -55
View File
@@ -40,67 +40,36 @@ commands:
sudo tar -C /usr/local -xf node-v10.15.1-linux-x64.tar.xz
sudo ln -s /usr/local/node-v10.15.1-linux-x64/bin/node /usr/bin/node
rm node-v10.15.1-linux-x64.tar.xz
dep:
steps:
- run:
name: "Install Go dependencies"
command: |
curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh
dep ensure --vendor-only
llvm-source-linux:
steps:
- restore_cache:
keys:
- llvm-source-8-v2
- llvm-source-8-v3
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-8-v2
key: llvm-source-8-v3
paths:
- llvm
smoketest:
steps:
- smoketest-no-avr
- run: tinygo build -size short -o test.elf -target=arduino examples/blinky1
- run: tinygo build -size short -o test.elf -target=digispark examples/blinky1
- run: make smoketest
smoketest-no-avr:
steps:
- run: tinygo build -size short -o test.elf -target=pca10040 examples/blinky1
- run: tinygo build -size short -o test.elf -target=pca10040 examples/blinky2
- run: tinygo build -o blinky2 examples/blinky2 # TODO: re-enable -size flag with MachO support
- run: tinygo build -size short -o test.elf -target=pca10040 examples/test
- run: tinygo build -size short -o test.elf -target=microbit examples/echo
- run: tinygo build -size short -o test.elf -target=nrf52840-mdk examples/blinky1
- run: tinygo build -size short -o test.elf -target=pca10031 examples/blinky1
- run: tinygo build -size short -o test.elf -target=bluepill examples/blinky1
- run: tinygo build -size short -o test.elf -target=reelboard examples/blinky1
- run: tinygo build -size short -o test.elf -target=reelboard examples/blinky2
- run: tinygo build -size short -o test.elf -target=pca10056 examples/blinky1
- run: tinygo build -size short -o test.elf -target=pca10056 examples/blinky2
- run: tinygo build -size short -o test.elf -target=itsybitsy-m0 examples/blinky1
- run: tinygo build -size short -o test.elf -target=circuitplay-express examples/blinky1
- run: tinygo build -size short -o test.elf -target=stm32f4disco examples/blinky1
- run: tinygo build -size short -o test.elf -target=stm32f4disco examples/blinky2
- run: tinygo build -size short -o test.elf -target=circuitplay-express examples/i2s
- run: tinygo build -o wasm.wasm -target=wasm examples/wasm/export
- run: tinygo build -o wasm.wasm -target=wasm examples/wasm/main
- run: make smoketest-no-avr
test-linux:
parameters:
llvm:
type: string
steps:
- checkout
- submodules
- apt-dependencies:
llvm: <<parameters.llvm>>
llvm: "-8"
- install-node
- restore_cache:
keys:
- go-cache-{{ checksum "Gopkg.lock" }}-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}
- go-cache-{{ checksum "Gopkg.lock" }}
- llvm-source-linux
- dep
- run: go install .
- run: go test -v
- run: make gen-device -j4
@@ -137,7 +106,7 @@ commands:
- llvm-source-linux
- restore_cache:
keys:
- llvm-build-8-linux-v4
- llvm-build-8-linux-v5
- run:
name: "Build LLVM"
command: |
@@ -155,7 +124,7 @@ commands:
make llvm-build
fi
- save_cache:
key: llvm-build-8-linux-v4
key: llvm-build-8-linux-v5
paths:
llvm-build
- run:
@@ -164,7 +133,6 @@ commands:
ln -s $PWD/llvm-build/bin/clang-8 /go/bin/clang-8
ln -s $PWD/llvm-build/bin/ld.lld /go/bin/ld.lld-8
ln -s $PWD/llvm-build/bin/wasm-ld /go/bin/wasm-ld-8
- dep
- run:
name: "Test TinyGo"
command: make test
@@ -195,20 +163,23 @@ commands:
- run:
name: "Install dependencies"
command: |
HOMEBREW_NO_AUTO_UPDATE=1 brew install go dep qemu
curl https://dl.google.com/go/go1.12.5.darwin-amd64.tar.gz -o go1.12.5.darwin-amd64.tar.gz
sudo tar -C /usr/local -xzf go1.12.5.darwin-amd64.tar.gz
ln -s /usr/local/go/bin/go /usr/local/bin/go
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu
- restore_cache:
keys:
- llvm-source-8-macos-v2
- llvm-source-8-macos-v3
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-8-macos-v2
key: llvm-source-8-macos-v3
paths:
- llvm
- restore_cache:
keys:
- llvm-build-8-macos-v3
- llvm-build-8-macos-v4
- run:
name: "Build LLVM"
command: |
@@ -220,16 +191,13 @@ commands:
make llvm-build
fi
- save_cache:
key: llvm-build-8-macos-v3
key: llvm-build-8-macos-v4
paths:
llvm-build
- run:
name: "Create LLVM symlinks"
command: |
ln -s $PWD/llvm-build/bin/clang-8 /usr/local/bin/clang-8
- run:
name: "Install Go dependencies"
command: dep ensure --vendor-only
- run:
name: "Test TinyGo"
command: make test
@@ -254,27 +222,21 @@ jobs:
test-llvm8-go111:
docker:
- image: circleci/golang:1.11
working_directory: /go/src/github.com/tinygo-org/tinygo
steps:
- test-linux:
llvm: "-8"
- test-linux
test-llvm8-go112:
docker:
- image: circleci/golang:1.12
working_directory: /go/src/github.com/tinygo-org/tinygo
steps:
- test-linux:
llvm: "-8"
- test-linux
build-linux:
docker:
- image: circleci/golang:1.12
working_directory: /go/src/github.com/tinygo-org/tinygo
steps:
- build-linux
build-macos:
macos:
xcode: "10.1.0"
working_directory: ~/go/src/github.com/tinygo-org/tinygo
steps:
- build-macos
+49
View File
@@ -1,3 +1,52 @@
0.6.0
---
* **command line**
- some portability improvements
- make `$GOROOT` more robust and configurable
- check for Clang at the Homebrew install location as fallback
* **compiler driver**
- support multiple variations of LLVM commands, for non-Debian distributions
* **compiler**
- improve code quality in multiple ways
- make panic configurable, adding trap on panic
- refactor many internal parts of the compiler
- print all errors encountered during compilation
- implement calling function values of a named type
- implement returning values from blocking functions
- allow larger-than-int values to be sent across a channel
- implement complex arithmetic
- improve hashmap support
- add debuginfo for function arguments
- insert nil checks on stores (increasing code size)
- implement volatile operations as compiler builtins
- add `//go:inline` pragma
- add build tags for the Go stdlib version
* **cgo**
- implement `char`, `enum` and `void*` types
- support `#include` for builtin headers
- improve typedef/struct/enum support
- only include symbols that are necessary, for broader support
- mark external function args as `nocapture`
- implement support for some `#define` constants
- implement support for multiple CGo files in a single package
- **standard library**
- `machine`: remove microbit matrix (moved to drivers repository)
- `machine`: refactor pins to use `Pin` type instead of `GPIO`
- `runtime`: print more interface types on panic, including `error`
* **targets**
- `arm`: print an error on HardFault (including stack overflows)
- `atsamd21`: fix a bug in the ADC peripheral
- `atsamd21`: add support for I2S
- `feather-m0`: add support for this board
- `nrf51`: fix a bug in I2C
- `stm32f103xx`: fix a bug in I2C
- `syscall`: implement `Exit` on unix
- `trinket-m0`: add support for this board
- `wasm`: make _main_ example smaller
- `wasm`: don't cache wasm file in the server, for ease of debugging
- `wasm`: work around bug #41508 that caused a deadlock while linking
- `wasm`: add support for `js.FuncOf`
0.5.0
---
- **compiler driver**
+3 -3
View File
@@ -46,7 +46,7 @@ RUN cd /go/src/github.com/tinygo-org/tinygo/ && \
apt-get update && \
apt-get install -y apt-utils python3 make binutils-avr gcc-avr avr-libc && \
make gen-device-avr && \
apt-get remove -y python3 make && \
apt-get remove -y python3 && \
apt-get autoremove -y && \
apt-get clean
@@ -64,7 +64,7 @@ RUN cd /go/src/github.com/tinygo-org/tinygo/ && \
apt-get update && \
apt-get install -y apt-utils python3 make clang-8 && \
make gen-device-nrf && make gen-device-stm32 && \
apt-get remove -y python3 make && \
apt-get remove -y python3 && \
apt-get autoremove -y && \
apt-get clean
@@ -79,7 +79,7 @@ RUN cd /go/src/github.com/tinygo-org/tinygo/ && \
apt-get update && \
apt-get install -y apt-utils python3 make clang-8 binutils-avr gcc-avr avr-libc && \
make gen-device && \
apt-get remove -y python3 make && \
apt-get remove -y python3 && \
apt-get autoremove -y && \
apt-get clean
+39
View File
@@ -84,6 +84,45 @@ build/tinygo:
test:
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" go test -v -tags byollvm .
.PHONY: smoketest smoketest-no-avr
smoketest: smoketest-no-avr
tinygo build -size short -o test.elf -target=arduino examples/blinky1
tinygo build -size short -o test.elf -target=digispark examples/blinky1
smoketest-no-avr:
# test all examples
tinygo build -size short -o test.elf -target=pca10040 examples/blinky1
tinygo build -size short -o test.elf -target=pca10040 examples/adc
tinygo build -size short -o test.elf -target=pca10040 examples/blinkm
tinygo build -size short -o test.elf -target=pca10040 examples/blinky2
tinygo build -size short -o test.elf -target=pca10040 examples/button
tinygo build -size short -o test.elf -target=pca10040 examples/button2
tinygo build -size short -o test.elf -target=pca10040 examples/echo
tinygo build -size short -o test.elf -target=circuitplay-express examples/i2s
tinygo build -size short -o test.elf -target=pca10040 examples/mcp3008
tinygo build -size short -o test.elf -target=microbit examples/microbit-blink
tinygo build -size short -o test.elf -target=pca10040 examples/pwm
tinygo build -size short -o test.elf -target=pca10040 examples/serial
tinygo build -size short -o test.elf -target=pca10040 examples/test
# test all targets/boards
tinygo build -o test.elf examples/blinky2 # TODO: re-enable -size flag with MachO support
tinygo build -size short -o test.elf -target=microbit examples/echo
tinygo build -size short -o test.elf -target=nrf52840-mdk examples/blinky1
tinygo build -size short -o test.elf -target=pca10031 examples/blinky1
tinygo build -size short -o test.elf -target=bluepill examples/blinky1
tinygo build -size short -o test.elf -target=reelboard examples/blinky1
tinygo build -size short -o test.elf -target=reelboard examples/blinky2
tinygo build -size short -o test.elf -target=pca10056 examples/blinky1
tinygo build -size short -o test.elf -target=pca10056 examples/blinky2
tinygo build -size short -o test.elf -target=itsybitsy-m0 examples/blinky1
tinygo build -size short -o test.elf -target=feather-m0 examples/blinky1
tinygo build -size short -o test.elf -target=trinket-m0 examples/blinky1
tinygo build -size short -o test.elf -target=circuitplay-express examples/blinky1
tinygo build -size short -o test.elf -target=stm32f4disco examples/blinky1
tinygo build -size short -o test.elf -target=stm32f4disco examples/blinky2
tinygo build -size short -o test.elf -target=circuitplay-express examples/i2s
tinygo build -o wasm.wasm -target=wasm examples/wasm/export
tinygo build -o wasm.wasm -target=wasm examples/wasm/main
release: build/tinygo gen-device
@mkdir -p build/release/tinygo/bin
@mkdir -p build/release/tinygo/lib/clang/include
+7 -4
View File
@@ -17,8 +17,8 @@ import (
)
func main() {
led := machine.GPIO{machine.LED}
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
for {
led.Low()
time.Sleep(time.Millisecond * 1000)
@@ -43,13 +43,16 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
The following microcontroller boards are currently supported:
The following 14 microcontroller boards are currently supported:
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
* [Adafruit Feather M0](https://www.adafruit.com/product/2772)
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
* [Adafruit Trinket M0](https://www.adafruit.com/product/3500)
* [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3)
* [BBC:Microbit](https://microbit.org/)
* [BBC micro:bit](https://microbit.org/)
* [ST Micro STM32F103XX "Bluepill"](http://wiki.stm32duino.com/index.php?title=Blue_Pill)
* [ST Micro STM32F407 "Discovery"](https://www.st.com/en/evaluation-tools/stm32f4discovery.html)
* [Digispark](http://digistump.com/products/1)
* [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)
+59
View File
@@ -35,6 +35,7 @@ type cgoPackage struct {
globals map[string]globalInfo
typedefs map[string]*typedefInfo
elaboratedTypes map[string]*elaboratedTypeInfo
enums map[string]enumInfo
}
// constantInfo stores some information about a CGo constant found by libclang
@@ -71,6 +72,12 @@ type elaboratedTypeInfo struct {
pos token.Pos
}
// enumInfo contains information about an enum in the C.
type enumInfo struct {
typeExpr ast.Expr
pos token.Pos
}
// globalInfo contains information about a declared global variable in C.
type globalInfo struct {
typeExpr ast.Expr
@@ -140,6 +147,7 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
globals: map[string]globalInfo{},
typedefs: map[string]*typedefInfo{},
elaboratedTypes: map[string]*elaboratedTypeInfo{},
enums: map[string]enumInfo{},
}
// Add a new location for the following file.
@@ -243,6 +251,9 @@ func Process(files []*ast.File, dir string, fset *token.FileSet, cflags []string
// Add elaborated types for C structs and unions.
p.addElaboratedTypes()
// Add enum types and enum constants for C enums.
p.addEnumTypes()
// Patch the AST to use the declared types and functions.
for _, f := range files {
astutil.Apply(f, p.walker, nil)
@@ -574,6 +585,54 @@ func (p *cgoPackage) addElaboratedTypes() {
p.generated.Decls = append(p.generated.Decls, gen)
}
// addEnumTypes adds C enums to the AST. For example, the following C code:
//
// enum option {
// optionA,
// optionB = 5,
// };
//
// is translated to the following Go code equivalent:
//
// type C.enum_option int32
//
// The constants are treated just like macros so are inserted into the AST by
// addConstDecls.
// See also: https://en.cppreference.com/w/c/language/enum
func (p *cgoPackage) addEnumTypes() {
if len(p.enums) == 0 {
return
}
gen := &ast.GenDecl{
TokPos: token.NoPos,
Tok: token.TYPE,
}
names := make([]string, 0, len(p.enums))
for name := range p.enums {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
typ := p.enums[name]
typeName := "C.enum_" + name
obj := &ast.Object{
Kind: ast.Typ,
Name: typeName,
}
typeSpec := &ast.TypeSpec{
Name: &ast.Ident{
NamePos: typ.pos,
Name: typeName,
Obj: obj,
},
Type: typ.typeExpr,
}
obj.Decl = typeSpec
gen.Specs = append(gen.Specs, typeSpec)
}
p.generated.Decls = append(p.generated.Decls, gen)
}
// findMissingCGoNames traverses the AST and finds all C.something names. Only
// these symbols are extracted from the parsed C AST and converted to the Go
// equivalent.
+51 -1
View File
@@ -49,9 +49,12 @@ GoCXCursor tinygo_clang_Cursor_getArgument(GoCXCursor c, unsigned i);
CXSourceLocation tinygo_clang_getCursorLocation(GoCXCursor c);
CXSourceRange tinygo_clang_getCursorExtent(GoCXCursor c);
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(GoCXCursor c);
long long tinygo_clang_getEnumConstantDeclValue(GoCXCursor c);
CXType tinygo_clang_getEnumDeclIntegerType(GoCXCursor c);
int tinygo_clang_globals_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
int tinygo_clang_struct_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
int tinygo_clang_enum_visitor(GoCXCursor c, GoCXCursor parent, CXClientData client_data);
*/
import "C"
@@ -501,6 +504,8 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
switch underlying.kind {
case C.CXType_Record:
return p.makeASTType(underlying, pos)
case C.CXType_Enum:
return p.makeASTType(underlying, pos)
default:
panic("unknown elaborated type")
}
@@ -580,11 +585,43 @@ func (p *cgoPackage) makeASTType(typ C.CXType, pos token.Pos) ast.Expr {
NamePos: pos,
Name: "C." + cgoName,
}
case C.CXType_Enum:
cursor := C.tinygo_clang_getTypeDeclaration(typ)
name := getString(C.tinygo_clang_getCursorSpelling(cursor))
underlying := C.tinygo_clang_getEnumDeclIntegerType(cursor)
if name == "" {
// anonymous enum
ref := storedRefs.Put(p)
defer storedRefs.Remove(ref)
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_enum_visitor), C.CXClientData(ref))
return p.makeASTType(underlying, pos)
} else {
// named enum
if _, ok := p.enums[name]; !ok {
ref := storedRefs.Put(p)
defer storedRefs.Remove(ref)
C.tinygo_clang_visitChildren(cursor, C.CXCursorVisitor(C.tinygo_clang_enum_visitor), C.CXClientData(ref))
p.enums[name] = enumInfo{
typeExpr: p.makeASTType(underlying, pos),
pos: pos,
}
}
return &ast.Ident{
NamePos: pos,
Name: "C.enum_" + name,
}
}
}
if typeName == "" {
// Report this as an error.
spelling := getString(C.clang_getTypeSpelling(typ))
p.errors = append(p.errors, scanner.Error{
Pos: p.fset.PositionFor(pos, true),
Msg: fmt.Sprintf("unknown C type: %v (libclang type kind %d)", spelling, typ.kind),
})
// Fallback, probably incorrect but at least the error points to an odd
// type name.
typeName = "C." + getString(C.clang_getTypeSpelling(typ))
typeName = "C." + spelling
}
return &ast.Ident{
NamePos: pos,
@@ -622,3 +659,16 @@ func tinygo_clang_struct_visitor(c, parent C.GoCXCursor, client_data C.CXClientD
fieldList.List = append(fieldList.List, field)
return C.CXChildVisit_Continue
}
//export tinygo_clang_enum_visitor
func tinygo_clang_enum_visitor(c, parent C.GoCXCursor, client_data C.CXClientData) C.int {
p := storedRefs.Get(unsafe.Pointer(client_data)).(*cgoPackage)
name := getString(C.tinygo_clang_getCursorSpelling(c))
pos := p.getCursorPosition(c)
value := C.tinygo_clang_getEnumConstantDeclValue(c)
p.constants[name] = constantInfo{
expr: &ast.BasicLit{pos, token.INT, strconv.FormatInt(int64(value), 10)},
pos: pos,
}
return C.CXChildVisit_Continue
}
+8
View File
@@ -56,3 +56,11 @@ CXSourceRange tinygo_clang_getCursorExtent(CXCursor c) {
CXTranslationUnit tinygo_clang_Cursor_getTranslationUnit(CXCursor c) {
return clang_Cursor_getTranslationUnit(c);
}
long long tinygo_clang_getEnumConstantDeclValue(CXCursor c) {
return clang_getEnumConstantDeclValue(c);
}
CXType tinygo_clang_getEnumDeclIntegerType(CXCursor c) {
return clang_getEnumDeclIntegerType(c);
}
+11
View File
@@ -4,6 +4,7 @@ import (
"errors"
"os"
"os/exec"
"runtime"
"strings"
)
@@ -15,6 +16,16 @@ var commands = map[string][]string{
"wasm-ld": {"wasm-ld-8", "wasm-ld"},
}
func init() {
// Add the path to a Homebrew-installed LLVM 8 for ease of use (no need to
// manually set $PATH).
if runtime.GOOS == "darwin" {
commands["clang"] = append(commands["clang"], "/usr/local/opt/llvm/bin/clang-8")
commands["ld.lld"] = append(commands["ld.lld"], "/usr/local/opt/llvm/bin/ld.lld")
commands["wasm-ld"] = append(commands["wasm-ld"], "/usr/local/opt/llvm/bin/wasm-ld")
}
}
func execCommand(cmdNames []string, args ...string) error {
for _, cmdName := range cmdNames {
cmd := exec.Command(cmdName, args...)
+8 -3
View File
@@ -42,7 +42,7 @@ func (c *Compiler) emitLookupBoundsCheck(frame *Frame, arrayLen, index llvm.Valu
// Fail: this is a nil pointer, exit with a panic.
c.builder.SetInsertPointAtEnd(faultBlock)
c.createRuntimeCall("lookuppanic", nil, "")
c.createRuntimeCall("lookupPanic", nil, "")
c.builder.CreateUnreachable()
// Ok: this is a valid pointer.
@@ -103,7 +103,7 @@ func (c *Compiler) emitSliceBoundsCheck(frame *Frame, capacity, low, high llvm.V
// Fail: this is a nil pointer, exit with a panic.
c.builder.SetInsertPointAtEnd(faultBlock)
c.createRuntimeCall("slicepanic", nil, "")
c.createRuntimeCall("slicePanic", nil, "")
c.builder.CreateUnreachable()
// Ok: this is a valid pointer.
@@ -114,6 +114,11 @@ func (c *Compiler) emitSliceBoundsCheck(frame *Frame, capacity, low, high llvm.V
// has no effect in well-behaved programs, but makes sure no uncaught nil
// pointer dereferences exist in valid Go code.
func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string) {
// Check whether we need to emit this check at all.
if !ptr.IsAGlobalValue().IsNil() {
return
}
// Check whether this is a nil pointer.
faultBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".nil")
nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".next")
@@ -141,7 +146,7 @@ func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string
// Fail: this is a nil pointer, exit with a panic.
c.builder.SetInsertPointAtEnd(faultBlock)
c.createRuntimeCall("nilpanic", nil, "")
c.createRuntimeCall("nilPanic", nil, "")
c.builder.CreateUnreachable()
// Ok: this is a valid pointer.
+13 -19
View File
@@ -23,47 +23,41 @@ func (c *Compiler) emitMakeChan(expr *ssa.MakeChan) (llvm.Value, error) {
// emitChanSend emits a pseudo chan send operation. It is lowered to the actual
// channel send operation during goroutine lowering.
func (c *Compiler) emitChanSend(frame *Frame, instr *ssa.Send) {
valueType := c.getLLVMType(instr.X.Type())
ch := c.getValue(frame, instr.Chan)
chanValue := c.getValue(frame, instr.X)
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(chanValue.Type()), false)
coroutine := c.createRuntimeCall("getCoroutine", nil, "")
// store value-to-send
c.builder.SetInsertPointBefore(coroutine.InstructionParent().Parent().EntryBasicBlock().FirstInstruction())
valueAlloca := c.builder.CreateAlloca(valueType, "chan.value")
c.builder.SetInsertPointBefore(coroutine)
c.builder.SetInsertPointAtEnd(coroutine.InstructionParent())
valueType := c.getLLVMType(instr.X.Type())
valueAlloca, valueAllocaCast, valueAllocaSize := c.createTemporaryAlloca(valueType, "chan.value")
c.builder.CreateStore(chanValue, valueAlloca)
valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr")
// Do the send.
coroutine := c.createRuntimeCall("getCoroutine", nil, "")
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(chanValue.Type()), false)
c.createRuntimeCall("chanSend", []llvm.Value{coroutine, ch, valueAllocaCast, valueSize}, "")
// Make sure CoroSplit includes the alloca in the coroutine frame.
// This is a bit dirty, but it works (at least in LLVM 8).
valueSizeI64 := llvm.ConstInt(c.ctx.Int64Type(), c.targetData.TypeAllocSize(chanValue.Type()), false)
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{valueSizeI64, valueAllocaCast}, "")
// End the lifetime of the alloca.
// This also works around a bug in CoroSplit, at least in LLVM 8:
// https://bugs.llvm.org/show_bug.cgi?id=41742
c.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
}
// emitChanRecv emits a pseudo chan receive operation. It is lowered to the
// actual channel receive operation during goroutine lowering.
func (c *Compiler) emitChanRecv(frame *Frame, unop *ssa.UnOp) llvm.Value {
valueType := c.getLLVMType(unop.X.Type().(*types.Chan).Elem())
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false)
ch := c.getValue(frame, unop.X)
coroutine := c.createRuntimeCall("getCoroutine", nil, "")
// Allocate memory to receive into.
c.builder.SetInsertPointBefore(coroutine.InstructionParent().Parent().EntryBasicBlock().FirstInstruction())
valueAlloca := c.builder.CreateAlloca(valueType, "chan.value")
c.builder.SetInsertPointBefore(coroutine)
c.builder.SetInsertPointAtEnd(coroutine.InstructionParent())
valueAllocaCast := c.builder.CreateBitCast(valueAlloca, c.i8ptrType, "chan.value.i8ptr")
valueAlloca, valueAllocaCast, valueAllocaSize := c.createTemporaryAlloca(valueType, "chan.value")
// Do the receive.
coroutine := c.createRuntimeCall("getCoroutine", nil, "")
valueSize := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(valueType), false)
c.createRuntimeCall("chanRecv", []llvm.Value{coroutine, ch, valueAllocaCast, valueSize}, "")
received := c.builder.CreateLoad(valueAlloca, "chan.received")
c.emitLifetimeEnd(valueAllocaCast, valueAllocaSize)
if unop.CommaOk {
commaOk := c.createRuntimeCall("getTaskPromiseData", []llvm.Value{coroutine}, "chan.commaOk.wide")
commaOk = c.builder.CreateTrunc(commaOk, c.ctx.Int1Type(), "chan.commaOk")
+28 -20
View File
@@ -30,6 +30,7 @@ func init() {
type Config struct {
Triple string // LLVM target triple, e.g. x86_64-unknown-linux-gnu (empty string means default)
CPU string // LLVM CPU name, e.g. atmega328p (empty string means default)
Features []string // LLVM CPU features
GOOS string //
GOARCH string //
GC string // garbage collection strategy
@@ -101,7 +102,11 @@ func NewCompiler(pkgName string, config Config) (*Compiler, error) {
if err != nil {
return nil, err
}
c.machine = target.CreateTargetMachine(config.Triple, config.CPU, "", llvm.CodeGenLevelDefault, llvm.RelocStatic, llvm.CodeModelDefault)
features := ""
if len(config.Features) > 0 {
features = strings.Join(config.Features, `,`)
}
c.machine = target.CreateTargetMachine(config.Triple, config.CPU, features, llvm.CodeGenLevelDefault, llvm.RelocStatic, llvm.CodeModelDefault)
c.targetData = c.machine.CreateTargetData()
c.ctx = llvm.NewContext()
@@ -151,15 +156,11 @@ func (c *Compiler) TargetData() llvm.TargetData {
func (c *Compiler) selectGC() string {
gc := c.GC
if gc == "" {
gc = "leaking"
gc = "dumb"
}
return gc
}
func (c *Compiler) gcIsPrecise() bool {
return c.GC == "precise"
}
// Compile the given package path or .go file path. Return an error when this
// fails (in any stage).
func (c *Compiler) Compile(mainPath string) []error {
@@ -824,6 +825,9 @@ func (c *Compiler) parseFunc(frame *Frame) {
if c.DumpSSA {
fmt.Printf("\nfunc %s:\n", frame.fn.Function)
}
if !frame.fn.LLVMFn.IsDeclaration() {
panic("function is already defined: " + frame.fn.LLVMFn.Name())
}
if !frame.fn.IsExported() {
frame.fn.LLVMFn.SetLinkage(llvm.InternalLinkage)
frame.fn.LLVMFn.SetUnnamedAddr(true)
@@ -1373,7 +1377,6 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
switch expr := expr.(type) {
case *ssa.Alloc:
typ := c.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem())
var buf llvm.Value
if expr.Heap {
size := c.targetData.TypeAllocSize(typ)
// Calculate ^uintptr(0)
@@ -1384,15 +1387,16 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
}
// TODO: escape analysis
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
buf = c.createRuntimeCall("alloc", []llvm.Value{sizeValue}, expr.Comment)
buf := c.createRuntimeCall("alloc", []llvm.Value{sizeValue}, expr.Comment)
buf = c.builder.CreateBitCast(buf, llvm.PointerType(typ, 0), "")
return buf, nil
} else {
buf = c.builder.CreateAlloca(typ, expr.Comment)
buf := c.createEntryBlockAlloca(typ, expr.Comment)
if c.targetData.TypeAllocSize(typ) != 0 {
c.builder.CreateStore(c.getZeroValue(typ), buf) // zero-initialize var
}
return buf, nil
}
return buf, nil
case *ssa.BinOp:
x := c.getValue(frame, expr.X)
y := c.getValue(frame, expr.Y)
@@ -1455,10 +1459,12 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// This could be done directly, but as this is a very infrequent
// operation it's much easier to bitcast it through an alloca.
resultType := c.getLLVMType(expr.Type())
alloca := c.builder.CreateAlloca(value.Type(), "")
alloca, allocaPtr, allocaSize := c.createTemporaryAlloca(value.Type(), "union.alloca")
c.builder.CreateStore(value, alloca)
bitcast := c.builder.CreateBitCast(alloca, llvm.PointerType(resultType, 0), "")
return c.builder.CreateLoad(bitcast, ""), nil
bitcast := c.builder.CreateBitCast(alloca, llvm.PointerType(resultType, 0), "union.bitcast")
result := c.builder.CreateLoad(bitcast, "union.result")
c.emitLifetimeEnd(allocaPtr, allocaSize)
return result, nil
}
result := c.builder.CreateExtractValue(value, expr.Field, "")
return result, nil
@@ -1498,11 +1504,13 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// Can't load directly from array (as index is non-constant), so have to
// do it using an alloca+gep+load.
alloca := c.builder.CreateAlloca(array.Type(), "index.alloca")
alloca, allocaPtr, allocaSize := c.createTemporaryAlloca(array.Type(), "index.alloca")
c.builder.CreateStore(array, alloca)
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
ptr := c.builder.CreateInBoundsGEP(alloca, []llvm.Value{zero, index}, "index.gep")
return c.builder.CreateLoad(ptr, "index.load"), nil
result := c.builder.CreateLoad(ptr, "index.load")
c.emitLifetimeEnd(allocaPtr, allocaSize)
return result, nil
case *ssa.IndexAddr:
val := c.getValue(frame, expr.X)
index := c.getValue(frame, expr.Index)
@@ -1662,16 +1670,16 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
llvmKeyType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Key())
llvmValueType := c.getLLVMType(rangeVal.Type().Underlying().(*types.Map).Elem())
mapKeyAlloca := c.builder.CreateAlloca(llvmKeyType, "range.key")
mapKeyPtr := c.builder.CreateBitCast(mapKeyAlloca, c.i8ptrType, "range.keyptr")
mapValueAlloca := c.builder.CreateAlloca(llvmValueType, "range.value")
mapValuePtr := c.builder.CreateBitCast(mapValueAlloca, c.i8ptrType, "range.valueptr")
mapKeyAlloca, mapKeyPtr, mapKeySize := c.createTemporaryAlloca(llvmKeyType, "range.key")
mapValueAlloca, mapValuePtr, mapValueSize := c.createTemporaryAlloca(llvmValueType, "range.value")
ok := c.createRuntimeCall("hashmapNext", []llvm.Value{llvmRangeVal, it, mapKeyPtr, mapValuePtr}, "range.next")
tuple := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.Int1Type(), llvmKeyType, llvmValueType}, false))
tuple = c.builder.CreateInsertValue(tuple, ok, 0, "")
tuple = c.builder.CreateInsertValue(tuple, c.builder.CreateLoad(mapKeyAlloca, ""), 1, "")
tuple = c.builder.CreateInsertValue(tuple, c.builder.CreateLoad(mapValueAlloca, ""), 2, "")
c.emitLifetimeEnd(mapKeyPtr, mapKeySize)
c.emitLifetimeEnd(mapValuePtr, mapValueSize)
return tuple, nil
}
case *ssa.Phi:
@@ -1688,7 +1696,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
default:
panic("unknown type in range: " + typ.String())
}
it := c.builder.CreateAlloca(iteratorType, "range.it")
it, _, _ := c.createTemporaryAlloca(iteratorType, "range.it")
c.builder.CreateStore(c.getZeroValue(iteratorType), it)
return it, nil
case *ssa.Select:
+4 -4
View File
@@ -154,17 +154,17 @@ func (c *Compiler) LowerFuncValues() {
// What we'll do is transform the following:
// rawPtr := runtime.getFuncPtr(fn)
// if func.rawPtr == nil {
// runtime.nilpanic()
// runtime.nilPanic()
// }
// result := func.rawPtr(...args, func.context)
// into this:
// if false {
// runtime.nilpanic()
// runtime.nilPanic()
// }
// var result // Phi
// switch fn.id {
// case 0:
// runtime.nilpanic()
// runtime.nilPanic()
// case 1:
// result = call first implementation...
// case 2:
@@ -222,7 +222,7 @@ func (c *Compiler) LowerFuncValues() {
// The 0 case, which is actually a nil check.
nilBlock := llvm.InsertBasicBlock(nextBlock, "func.nil")
c.builder.SetInsertPointAtEnd(nilBlock)
c.createRuntimeCall("nilpanic", nil, "")
c.createRuntimeCall("nilPanic", nil, "")
c.builder.CreateUnreachable()
sw.AddCase(llvm.ConstInt(c.uintptrType, 0, false), nilBlock)
-104
View File
@@ -1,104 +0,0 @@
package compiler
import (
"math/big"
"tinygo.org/x/go-llvm"
)
func (c *Compiler) addGlobalsBitmap() {
if c.mod.NamedGlobal("runtime.trackedGlobalsStart").IsNil() {
return // nothing to do: no GC in use
}
var trackedGlobals []llvm.Value
var trackedGlobalTypes []llvm.Type
for global := c.mod.FirstGlobal(); !global.IsNil(); global = llvm.NextGlobal(global) {
if global.IsDeclaration() {
continue
}
typ := global.Type().ElementType()
ptrs := c.getPointerBitmap(typ, global.Name())
if ptrs.BitLen() == 0 {
continue
}
trackedGlobals = append(trackedGlobals, global)
trackedGlobalTypes = append(trackedGlobalTypes, typ)
}
//
globalsBundleType := c.ctx.StructType(trackedGlobalTypes, false)
globalsBundle := llvm.AddGlobal(c.mod, globalsBundleType, "tinygo.trackedGlobals")
globalsBundle.SetLinkage(llvm.InternalLinkage)
globalsBundle.SetUnnamedAddr(true)
initializer := llvm.Undef(globalsBundleType)
for i, global := range trackedGlobals {
initializer = llvm.ConstInsertValue(initializer, global.Initializer(), []uint32{uint32(i)})
gep := llvm.ConstGEP(globalsBundle, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), uint64(i), false),
})
global.ReplaceAllUsesWith(gep)
global.EraseFromParentAsGlobal()
}
globalsBundle.SetInitializer(initializer)
trackedGlobalsStart := llvm.ConstPtrToInt(globalsBundle, c.uintptrType)
c.mod.NamedGlobal("runtime.trackedGlobalsStart").SetInitializer(trackedGlobalsStart)
alignment := c.targetData.PrefTypeAlignment(c.i8ptrType)
trackedGlobalsLength := llvm.ConstInt(c.uintptrType, c.targetData.TypeAllocSize(globalsBundleType)/uint64(alignment), false)
c.mod.NamedGlobal("runtime.trackedGlobalsLength").SetInitializer(trackedGlobalsLength)
bitmapBytes := c.getPointerBitmap(globalsBundleType, "globals bundle").Bytes()
bitmapValues := make([]llvm.Value, len(bitmapBytes))
for i, b := range bitmapBytes {
bitmapValues[len(bitmapBytes)-i-1] = llvm.ConstInt(c.ctx.Int8Type(), uint64(b), false)
}
bitmapArray := llvm.ConstArray(llvm.ArrayType(c.ctx.Int8Type(), len(bitmapBytes)), bitmapValues)
bitmapNew := llvm.AddGlobal(c.mod, bitmapArray.Type(), "runtime.trackedGlobalsBitmap.tmp")
bitmapOld := c.mod.NamedGlobal("runtime.trackedGlobalsBitmap")
bitmapOld.ReplaceAllUsesWith(bitmapNew)
bitmapNew.SetInitializer(bitmapArray)
bitmapNew.SetName("runtime.trackedGlobalsBitmap")
}
func (c *Compiler) getPointerBitmap(typ llvm.Type, name string) *big.Int {
alignment := c.targetData.PrefTypeAlignment(c.i8ptrType)
switch typ.TypeKind() {
case llvm.IntegerTypeKind, llvm.FloatTypeKind, llvm.DoubleTypeKind:
return big.NewInt(0)
case llvm.PointerTypeKind:
return big.NewInt(1)
case llvm.StructTypeKind:
ptrs := big.NewInt(0)
for i, subtyp := range typ.StructElementTypes() {
subptrs := c.getPointerBitmap(subtyp, name)
if subptrs.BitLen() == 0 {
continue
}
offset := c.targetData.ElementOffset(typ, i)
if offset%uint64(alignment) != 0 {
panic("precise GC: global contains unaligned pointer: " + name)
}
subptrs.Lsh(subptrs, uint(offset)/uint(alignment))
ptrs.Or(ptrs, subptrs)
}
return ptrs
case llvm.ArrayTypeKind:
subtyp := typ.ElementType()
subptrs := c.getPointerBitmap(subtyp, name)
ptrs := big.NewInt(0)
if subptrs.BitLen() == 0 {
return ptrs
}
elementSize := c.targetData.TypeAllocSize(subtyp)
for i := 0; i < typ.ArrayLength(); i++ {
ptrs.Lsh(ptrs, uint(elementSize)/uint(alignment))
ptrs.Or(ptrs, subptrs)
}
return ptrs
default:
panic("unknown type kind of global: " + name)
}
}
+16 -3
View File
@@ -389,7 +389,20 @@ func (c *Compiler) markAsyncFunctions() (needsScheduler bool, err error) {
c.builder.SetInsertPointBefore(inst)
parentHandle := f.LastParam()
var parentHandle llvm.Value
if f.Linkage() == llvm.ExternalLinkage {
// Exported function.
// Note that getTaskPromisePtr will panic if it is called with
// a nil pointer, so blocking exported functions that try to
// return anything will not work.
parentHandle = llvm.ConstPointerNull(c.i8ptrType)
} else {
parentHandle = f.LastParam()
if parentHandle.IsNil() || parentHandle.Name() != "parentHandle" {
// sanity check
panic("trying to make exported function async")
}
}
// Store return values.
switch inst.OperandsCount() {
@@ -417,7 +430,7 @@ func (c *Compiler) markAsyncFunctions() (needsScheduler bool, err error) {
// behavior somehow (with the unreachable instruction).
continuePoint := c.builder.CreateCall(coroSuspendFunc, []llvm.Value{
llvm.ConstNull(c.ctx.TokenType()),
llvm.ConstInt(c.ctx.Int1Type(), 1, false),
llvm.ConstInt(c.ctx.Int1Type(), 0, false),
}, "ret")
sw := c.builder.CreateSwitch(continuePoint, frame.suspendBlock, 2)
sw.AddCase(llvm.ConstInt(c.ctx.Int8Type(), 0, false), frame.unreachableBlock)
@@ -488,7 +501,7 @@ func (c *Compiler) markAsyncFunctions() (needsScheduler bool, err error) {
c.builder.SetInsertPointBefore(deadlockCall)
continuePoint := c.builder.CreateCall(coroSuspendFunc, []llvm.Value{
llvm.ConstNull(c.ctx.TokenType()),
llvm.ConstInt(c.ctx.Int1Type(), 1, false), // final suspend
llvm.ConstInt(c.ctx.Int1Type(), 0, false),
}, "")
c.splitBasicBlock(deadlockCall, llvm.NextBasicBlock(c.builder.GetInsertBlock()), "task.wakeup.dead")
c.builder.SetInsertPointBefore(deadlockCall)
+27 -9
View File
@@ -24,23 +24,41 @@ func getUses(value llvm.Value) []llvm.Value {
// createEntryBlockAlloca creates a new alloca in the entry block, even though
// the IR builder is located elsewhere. It assumes that the insert point is
// after the last instruction in the current block. Also, it adds lifetime
// information to the IR signalling that the alloca won't be used before this
// point.
// at the end of the current block.
func (c *Compiler) createEntryBlockAlloca(t llvm.Type, name string) llvm.Value {
currentBlock := c.builder.GetInsertBlock()
entryBlock := currentBlock.Parent().EntryBasicBlock()
if entryBlock.FirstInstruction().IsNil() {
c.builder.SetInsertPointAtEnd(entryBlock)
} else {
c.builder.SetInsertPointBefore(entryBlock.FirstInstruction())
}
alloca := c.builder.CreateAlloca(t, name)
c.builder.SetInsertPointAtEnd(currentBlock)
return alloca
}
// createTemporaryAlloca creates a new alloca in the entry block and adds
// lifetime start infromation in the IR signalling that the alloca won't be used
// before this point.
//
// This is useful for creating temporary allocas for intrinsics. Don't forget to
// end the lifetime after you're done with it.
func (c *Compiler) createEntryBlockAlloca(t llvm.Type, name string) (alloca, bitcast, size llvm.Value) {
currentBlock := c.builder.GetInsertBlock()
c.builder.SetInsertPointBefore(currentBlock.Parent().EntryBasicBlock().FirstInstruction())
alloca = c.builder.CreateAlloca(t, name)
c.builder.SetInsertPointAtEnd(currentBlock)
// end the lifetime using emitLifetimeEnd after you're done with it.
func (c *Compiler) createTemporaryAlloca(t llvm.Type, name string) (alloca, bitcast, size llvm.Value) {
alloca = c.createEntryBlockAlloca(t, name)
bitcast = c.builder.CreateBitCast(alloca, c.i8ptrType, name+".bitcast")
size = llvm.ConstInt(c.ctx.Int64Type(), c.targetData.TypeAllocSize(t), false)
c.builder.CreateCall(c.getLifetimeStartFunc(), []llvm.Value{size, bitcast}, "")
return
}
// emitLifetimeEnd signals the end of an (alloca) lifetime by calling the
// llvm.lifetime.end intrinsic. It is commonly used together with
// createTemporaryAlloca.
func (c *Compiler) emitLifetimeEnd(ptr, size llvm.Value) {
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{size, ptr}, "")
}
// getLifetimeStartFunc returns the llvm.lifetime.start intrinsic and creates it
// first if it doesn't exist yet.
func (c *Compiler) getLifetimeStartFunc() llvm.Value {
+10 -10
View File
@@ -15,7 +15,7 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
// Allocate the memory for the resulting type. Do not zero this memory: it
// will be zeroed by the hashmap get implementation if the key is not
// present in the map.
mapValueAlloca, mapValuePtr, mapValueSize := c.createEntryBlockAlloca(llvmValueType, "hashmap.value")
mapValueAlloca, mapValuePtr, mapValueSize := c.createTemporaryAlloca(llvmValueType, "hashmap.value")
// Do the lookup. How it is done depends on the key type.
var commaOkValue llvm.Value
@@ -27,12 +27,12 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
// key can be compared with runtime.memequal
// Store the key in an alloca, in the entry block to avoid dynamic stack
// growth.
mapKeyAlloca, mapKeyPtr, mapKeySize := c.createEntryBlockAlloca(key.Type(), "hashmap.key")
mapKeyAlloca, mapKeyPtr, mapKeySize := c.createTemporaryAlloca(key.Type(), "hashmap.key")
c.builder.CreateStore(key, mapKeyAlloca)
// Fetch the value from the hashmap.
params := []llvm.Value{m, mapKeyPtr, mapValuePtr}
commaOkValue = c.createRuntimeCall("hashmapBinaryGet", params, "")
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{mapKeySize, mapKeyPtr}, "")
c.emitLifetimeEnd(mapKeyPtr, mapKeySize)
} else {
// Not trivially comparable using memcmp.
return llvm.Value{}, c.makeError(pos, "only strings, bools, ints or structs of bools/ints are supported as map keys, but got: "+keyType.String())
@@ -41,7 +41,7 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
// Load the resulting value from the hashmap. The value is set to the zero
// value if the key doesn't exist in the hashmap.
mapValue := c.builder.CreateLoad(mapValueAlloca, "")
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{mapValueSize, mapValuePtr}, "")
c.emitLifetimeEnd(mapValuePtr, mapValueSize)
if commaOk {
tuple := llvm.Undef(c.ctx.StructType([]llvm.Type{llvmValueType, c.ctx.Int1Type()}, false))
@@ -54,7 +54,7 @@ func (c *Compiler) emitMapLookup(keyType, valueType types.Type, m, key llvm.Valu
}
func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value, pos token.Pos) {
valueAlloca, valuePtr, valueSize := c.createEntryBlockAlloca(value.Type(), "hashmap.value")
valueAlloca, valuePtr, valueSize := c.createTemporaryAlloca(value.Type(), "hashmap.value")
c.builder.CreateStore(value, valueAlloca)
keyType = keyType.Underlying()
if t, ok := keyType.(*types.Basic); ok && t.Info()&types.IsString != 0 {
@@ -63,15 +63,15 @@ func (c *Compiler) emitMapUpdate(keyType types.Type, m, key, value llvm.Value, p
c.createRuntimeCall("hashmapStringSet", params, "")
} else if hashmapIsBinaryKey(keyType) {
// key can be compared with runtime.memequal
keyAlloca, keyPtr, keySize := c.createEntryBlockAlloca(key.Type(), "hashmap.key")
keyAlloca, keyPtr, keySize := c.createTemporaryAlloca(key.Type(), "hashmap.key")
c.builder.CreateStore(key, keyAlloca)
params := []llvm.Value{m, keyPtr, valuePtr}
c.createRuntimeCall("hashmapBinarySet", params, "")
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{keySize, keyPtr}, "")
c.emitLifetimeEnd(keyPtr, keySize)
} else {
c.addError(pos, "only strings, bools, ints or structs of bools/ints are supported as map keys, but got: "+keyType.String())
}
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{valueSize, valuePtr}, "")
c.emitLifetimeEnd(valuePtr, valueSize)
}
func (c *Compiler) emitMapDelete(keyType types.Type, m, key llvm.Value, pos token.Pos) error {
@@ -82,11 +82,11 @@ func (c *Compiler) emitMapDelete(keyType types.Type, m, key llvm.Value, pos toke
c.createRuntimeCall("hashmapStringDelete", params, "")
return nil
} else if hashmapIsBinaryKey(keyType) {
keyAlloca, keyPtr, keySize := c.createEntryBlockAlloca(key.Type(), "hashmap.key")
keyAlloca, keyPtr, keySize := c.createTemporaryAlloca(key.Type(), "hashmap.key")
c.builder.CreateStore(key, keyAlloca)
params := []llvm.Value{m, keyPtr}
c.createRuntimeCall("hashmapBinaryDelete", params, "")
c.builder.CreateCall(c.getLifetimeEndFunc(), []llvm.Value{keySize, keyPtr}, "")
c.emitLifetimeEnd(keyPtr, keySize)
return nil
} else {
return c.makeError(pos, "only strings, bools, ints or structs of bools/ints are supported as map keys, but got: "+keyType.String())
-8
View File
@@ -37,7 +37,6 @@ func (c *Compiler) Optimize(optLevel, sizeLevel int, inlinerThreshold uint) erro
goPasses := llvm.NewPassManager()
defer goPasses.Dispose()
goPasses.AddGlobalOptimizerPass()
goPasses.AddGlobalDCEPass()
goPasses.AddConstantPropagationPass()
goPasses.AddAggressiveDCEPass()
goPasses.AddFunctionAttrsPass()
@@ -115,13 +114,6 @@ func (c *Compiler) Optimize(optLevel, sizeLevel int, inlinerThreshold uint) erro
builder.Populate(modPasses)
modPasses.Run(c.mod)
if c.gcIsPrecise() {
c.addGlobalsBitmap()
if err := c.Verify(); err != nil {
return errors.New("GC pass caused a verification failure")
}
}
return nil
}
+16 -7
View File
@@ -25,7 +25,7 @@ func (c *Compiler) emitPointerPack(values []llvm.Value) llvm.Value {
return llvm.ConstPointerNull(c.i8ptrType)
} else if len(values) == 1 && values[0].Type().TypeKind() == llvm.PointerTypeKind {
return c.builder.CreateBitCast(values[0], c.i8ptrType, "pack.ptr")
} else if size <= c.targetData.TypeAllocSize(c.i8ptrType) && !c.gcIsPrecise() {
} else if size <= c.targetData.TypeAllocSize(c.i8ptrType) {
// Packed data fits in a pointer, so store it directly inside the
// pointer.
if len(values) == 1 && values[0].Type().TypeKind() == llvm.IntegerTypeKind {
@@ -34,7 +34,7 @@ func (c *Compiler) emitPointerPack(values []llvm.Value) llvm.Value {
}
// Because packedType is a struct and we have to cast it to a *i8, store
// it in an alloca first for bitcasting (store+bitcast+load).
packedAlloc = c.builder.CreateAlloca(packedType, "")
packedAlloc, _, _ = c.createTemporaryAlloca(packedType, "")
} else {
// Packed data is bigger than a pointer, so allocate it on the heap.
sizeValue := llvm.ConstInt(c.uintptrType, size, false)
@@ -54,10 +54,14 @@ func (c *Compiler) emitPointerPack(values []llvm.Value) llvm.Value {
if packedHeapAlloc.IsNil() {
// Load value (as *i8) from the alloca.
packedAlloc = c.builder.CreateBitCast(packedAlloc, llvm.PointerType(c.i8ptrType, 0), "")
return c.builder.CreateLoad(packedAlloc, "")
result := c.builder.CreateLoad(packedAlloc, "")
packedPtr := c.builder.CreateBitCast(packedAlloc, c.i8ptrType, "")
packedSize := llvm.ConstInt(c.ctx.Int64Type(), c.targetData.TypeAllocSize(packedAlloc.Type()), false)
c.emitLifetimeEnd(packedPtr, packedSize)
return result
} else {
// Get the original heap allocation pointer, which already is an *i8.
return c.builder.CreateBitCast(packedAlloc, c.i8ptrType, "")
return packedHeapAlloc
}
}
@@ -66,21 +70,21 @@ func (c *Compiler) emitPointerUnpack(ptr llvm.Value, valueTypes []llvm.Type) []l
packedType := c.ctx.StructType(valueTypes, false)
// Get a correctly-typed pointer to the packed data.
var packedAlloc llvm.Value
var packedAlloc, packedRawAlloc llvm.Value
size := c.targetData.TypeAllocSize(packedType)
if size == 0 {
// No data to unpack.
} else if len(valueTypes) == 1 && valueTypes[0].TypeKind() == llvm.PointerTypeKind {
// A single pointer is always stored directly.
return []llvm.Value{c.builder.CreateBitCast(ptr, valueTypes[0], "unpack.ptr")}
} else if size <= c.targetData.TypeAllocSize(c.i8ptrType) && !c.gcIsPrecise() {
} else if size <= c.targetData.TypeAllocSize(c.i8ptrType) {
// Packed data stored directly in pointer.
if len(valueTypes) == 1 && valueTypes[0].TypeKind() == llvm.IntegerTypeKind {
// Keep this cast in SSA form.
return []llvm.Value{c.builder.CreatePtrToInt(ptr, valueTypes[0], "unpack.int")}
}
// Fallback: load it using an alloca.
packedRawAlloc := c.builder.CreateAlloca(llvm.PointerType(c.i8ptrType, 0), "unpack.raw.alloc")
packedRawAlloc, _, _ = c.createTemporaryAlloca(llvm.PointerType(c.i8ptrType, 0), "unpack.raw.alloc")
packedRawValue := c.builder.CreateBitCast(ptr, llvm.PointerType(c.i8ptrType, 0), "unpack.raw.value")
c.builder.CreateStore(packedRawValue, packedRawAlloc)
packedAlloc = c.builder.CreateBitCast(packedRawAlloc, llvm.PointerType(packedType, 0), "unpack.alloc")
@@ -104,5 +108,10 @@ func (c *Compiler) emitPointerUnpack(ptr llvm.Value, valueTypes []llvm.Type) []l
gep := c.builder.CreateInBoundsGEP(packedAlloc, indices, "")
values[i] = c.builder.CreateLoad(gep, "")
}
if !packedRawAlloc.IsNil() {
allocPtr := c.builder.CreateBitCast(packedRawAlloc, c.i8ptrType, "")
allocSize := llvm.ConstInt(c.ctx.Int64Type(), c.targetData.TypeAllocSize(c.uintptrType), false)
c.emitLifetimeEnd(allocPtr, allocSize)
}
return values
}
+10
View File
@@ -0,0 +1,10 @@
module github.com/tinygo-org/tinygo
go 1.11
require (
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261
)
+14
View File
@@ -0,0 +1,14 @@
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46 h1:wXG2bA8fO7Vv7lLk2PihFMTqmbT173Tje39oKzQ50Mo=
github.com/marcinbor85/gohex v0.0.0-20180128172054-7a43cd876e46/go.mod h1:Pb6XcsXyropB9LNHhnqaknG/vEwYztLkQzVCHv8sQ3M=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef h1:ymc9FeDom3RIEA3coKokSllBB1hRcMT0tZ1W3Jf9Ids=
golang.org/x/tools v0.0.0-20190227180812-8dcc6e70cdef/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261 h1:rJS2Hga39YAnm7DE4qrPm6Dr/67EOojL0XPzvbEeBiw=
tinygo.org/x/go-llvm v0.0.0-20190224120431-7707ae5d1261/go.mod h1:fv1F0BSNpxMfCL0zF3M4OPFbgYHnhtB6ST0HvUtu/LE=
+33 -10
View File
@@ -184,6 +184,25 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
lhs := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
rhs := fr.getLocal(inst.Operand(1)).(*LocalValue).Underlying
predicate := inst.IntPredicate()
if predicate == llvm.IntEQ && lhs.Type().TypeKind() == llvm.PointerTypeKind {
// Unfortunately, the const propagation in the IR builder
// doesn't handle pointer compares of inttoptr values. So we
// implement it manually here.
lhsNil, ok1 := isPointerNil(lhs)
rhsNil, ok2 := isPointerNil(rhs)
if ok1 && ok2 {
if lhsNil && rhsNil {
// Both are nil, so this icmp is always evaluated to true.
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 1, false)}
continue
}
if lhsNil != rhsNil {
// Only one of them is nil, so this comparison must return false.
fr.locals[inst] = &LocalValue{fr.Eval, llvm.ConstInt(fr.Mod.Context().Int1Type(), 0, false)}
continue
}
}
}
fr.locals[inst] = &LocalValue{fr.Eval, fr.builder.CreateICmp(predicate, lhs, rhs, "")}
case !inst.IsAFCmpInst().IsNil():
lhs := fr.getLocal(inst.Operand(0)).(*LocalValue).Underlying
@@ -461,17 +480,21 @@ func (fr *frame) evalBasicBlock(bb, incoming llvm.BasicBlock, indent string) (re
}
thenBB := inst.Operand(1)
elseBB := inst.Operand(2)
if !cond.IsConstant() {
if !cond.IsAInstruction().IsNil() {
return nil, nil, errors.New("interp: branch on a non-constant")
} else {
switch cond.ZExtValue() {
case 0: // false
return nil, []llvm.Value{thenBB}, nil // then
case 1: // true
return nil, []llvm.Value{elseBB}, nil // else
default:
panic("branch was not true or false")
}
}
if !cond.IsAConstantExpr().IsNil() {
// This may happen when the instruction builder could not
// const-fold some instructions.
return nil, nil, errors.New("interp: branch on a non-const-propagated constant expression")
}
switch cond {
case llvm.ConstInt(fr.Mod.Context().Int1Type(), 0, false): // false
return nil, []llvm.Value{thenBB}, nil // then
case llvm.ConstInt(fr.Mod.Context().Int1Type(), 1, false): // true
return nil, []llvm.Value{elseBB}, nil // else
default:
panic("branch was not true or false")
}
case !inst.IsABranchInst().IsNil() && inst.OperandsCount() == 1:
// unconditional branch (goto)
+10 -1
View File
@@ -109,7 +109,16 @@ func (e *Eval) hasSideEffects(fn llvm.Value) *sideEffectResult {
default:
panic("unreachable")
}
case llvm.Load, llvm.Store:
case llvm.Load:
if inst.IsVolatile() {
result.updateSeverity(sideEffectLimited)
}
if _, ok := e.dirtyGlobals[inst.Operand(0)]; ok {
if e.hasLocalSideEffects(dirtyLocals, inst) {
result.updateSeverity(sideEffectLimited)
}
}
case llvm.Store:
if inst.IsVolatile() {
result.updateSeverity(sideEffectLimited)
}
+26
View File
@@ -94,3 +94,29 @@ func isScalar(t llvm.Type) bool {
return false
}
}
// isPointerNil returns whether this is a nil pointer or not. The ok value
// indicates whether the result is certain: if it is false the result boolean is
// not valid.
func isPointerNil(v llvm.Value) (result bool, ok bool) {
if !v.IsAConstantExpr().IsNil() {
switch v.Opcode() {
case llvm.IntToPtr:
// Whether a constant inttoptr is nil is easy to
// determine.
operand := v.Operand(0)
if operand.IsConstant() {
return operand.ZExtValue() == 0, true
}
case llvm.BitCast, llvm.GetElementPtr:
// These const instructions are just a kind of wrappers for the
// underlying pointer.
return isPointerNil(v.Operand(0))
}
}
if !v.IsAConstantPointerNull().IsNil() {
// A constant pointer null is always null, of course.
return true, true
}
return false, false // not valid
}
+14 -2
View File
@@ -80,9 +80,21 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
if goroot == "" {
return errors.New("cannot locate $GOROOT, please set it manually")
}
tags := spec.BuildTags
major, minor := getGorootVersion(goroot)
if major != 1 {
if major == 0 {
return errors.New("could not read version from GOROOT: " + goroot)
}
return fmt.Errorf("expected major version 1, got go%d.%d", major, minor)
}
for i := 1; i <= minor; i++ {
tags = append(tags, fmt.Sprintf("go1.%d", i))
}
compilerConfig := compiler.Config{
Triple: spec.Triple,
CPU: spec.CPU,
Features: spec.Features,
GOOS: spec.GOOS,
GOARCH: spec.GOARCH,
GC: config.gc,
@@ -94,7 +106,7 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
TINYGOROOT: root,
GOROOT: goroot,
GOPATH: getGopath(),
BuildTags: spec.BuildTags,
BuildTags: tags,
}
c, err := compiler.NewCompiler(pkgName, compilerConfig)
if err != nil {
@@ -537,7 +549,7 @@ func handleCompilerError(err error) {
func main() {
outpath := flag.String("o", "", "output filename")
opt := flag.String("opt", "z", "optimization level: 0, 1, 2, s, z")
gc := flag.String("gc", "", "garbage collector to use (none, leaking, conservative)")
gc := flag.String("gc", "", "garbage collector to use (none, dumb, marksweep)")
panicStrategy := flag.String("panic", "print", "panic strategy (abort, trap)")
printIR := flag.Bool("printir", false, "print LLVM IR")
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
-3
View File
@@ -58,9 +58,6 @@ func TestCompiler(t *testing.T) {
t.Log("running tests for emulated cortex-m3...")
for _, path := range matches {
if path == "testdata/reflect.go" {
continue
}
t.Run(path, func(t *testing.T) {
runTest(path, tmpdir, "qemu", t)
})
+21
View File
@@ -0,0 +1,21 @@
.syntax unified
.section .text.HardFault_Handler
.global HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
// Put the old stack pointer in the first argument, for easy debugging. This
// is especially useful on Cortex-M0, which supports far fewer debug
// facilities.
mov r0, sp
// Load the default stack pointer from address 0 so that we can call normal
// functions again that expect a working stack. However, it will corrupt the
// old stack so the function below must not attempt to recover from this
// fault.
movs r3, #0
ldr r3, [r3]
mov sp, r3
// Continue handling this error in Go.
bl handleHardFault
+2 -2
View File
@@ -11,8 +11,8 @@ import (
func main() {
machine.InitADC()
led := machine.GPIO{machine.LED}
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
sensor := machine.ADC{machine.ADC2}
sensor.Configure()
+2 -2
View File
@@ -8,8 +8,8 @@ import (
)
func main() {
led := machine.GPIO{machine.LED}
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
for {
led.Low()
time.Sleep(time.Millisecond * 500)
+4 -4
View File
@@ -16,8 +16,8 @@ func main() {
}
func led1() {
led := machine.GPIO{machine.LED}
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
led := machine.LED1
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
for {
println("+")
led.Low()
@@ -30,8 +30,8 @@ func led1() {
}
func led2() {
led := machine.GPIO{machine.LED2}
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
led := machine.LED2
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
for {
println(" +")
led.Low()
+6 -6
View File
@@ -7,14 +7,14 @@ import (
// This example assumes that the button is connected to pin 8. Change the value
// below to use a different pin.
const buttonPin = 8
const (
led = machine.LED
button = machine.Pin(8)
)
func main() {
led := machine.GPIO{machine.LED}
led.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
button := machine.GPIO{buttonPin}
button.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT})
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
button.Configure(machine.PinConfig{Mode: machine.PinInput})
for {
if button.Get() {
+16 -16
View File
@@ -8,29 +8,29 @@ import (
// This example assumes that you are using the pca10040 board
func main() {
led1 := machine.GPIO{machine.LED1}
led1.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
led1 := machine.LED1
led1.Configure(machine.PinConfig{Mode: machine.PinOutput})
led2 := machine.GPIO{machine.LED2}
led2.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
led2 := machine.LED2
led2.Configure(machine.PinConfig{Mode: machine.PinOutput})
led3 := machine.GPIO{machine.LED3}
led3.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
led3 := machine.LED3
led3.Configure(machine.PinConfig{Mode: machine.PinOutput})
led4 := machine.GPIO{machine.LED4}
led4.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
led4 := machine.LED4
led4.Configure(machine.PinConfig{Mode: machine.PinOutput})
button1 := machine.GPIO{machine.BUTTON1}
button1.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT_PULLUP})
button1 := machine.BUTTON1
button1.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
button2 := machine.GPIO{machine.BUTTON2}
button2.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT_PULLUP})
button2 := machine.BUTTON2
button2.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
button3 := machine.GPIO{machine.BUTTON3}
button3.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT_PULLUP})
button3 := machine.BUTTON3
button3.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
button4 := machine.GPIO{machine.BUTTON4}
button4.Configure(machine.GPIOConfig{Mode: machine.GPIO_INPUT_PULLUP})
button4 := machine.BUTTON4
button4.Configure(machine.PinConfig{Mode: machine.PinInputPullup})
for {
led1.Set(button1.Get())
+3 -3
View File
@@ -9,9 +9,9 @@ import (
// change these to test a different UART or pins if available
var (
uart = machine.UART0
tx uint8 = machine.UART_TX_PIN
rx uint8 = machine.UART_RX_PIN
uart = machine.UART0
tx = machine.UART_TX_PIN
rx = machine.UART_RX_PIN
)
func main() {
+3 -5
View File
@@ -8,19 +8,17 @@ import (
"time"
)
// CS_PIN is the pin used for Chip Select (CS). Change to whatever is in use on your board.
const CS_PIN = 3
// cs is the pin used for Chip Select (CS). Change to whatever is in use on your board.
const cs = machine.Pin(3)
var (
tx []byte
rx []byte
val, result uint16
cs machine.GPIO
)
func main() {
cs = machine.GPIO{CS_PIN}
cs.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
machine.SPI0.Configure(machine.SPIConfig{
Frequency: 4000000,
@@ -9,10 +9,10 @@ import (
// The LED matrix in the micro:bit is a multiplexed display: https://en.wikipedia.org/wiki/Multiplexed_display
// Driver for easier control: https://github.com/tinygo-org/drivers/tree/master/microbitmatrix
func main() {
ledrow := machine.GPIO{machine.LED_ROW_1}
ledrow.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
ledcol := machine.GPIO{machine.LED_COL_1}
ledcol.Configure(machine.GPIOConfig{Mode: machine.GPIO_OUTPUT})
ledrow := machine.LED_ROW_1
ledrow.Configure(machine.PinConfig{Mode: machine.PinOutput})
ledcol := machine.LED_COL_1
ledcol.Configure(machine.PinConfig{Mode: machine.PinOutput})
ledcol.Low()
for {
ledrow.Low()
+7 -2
View File
@@ -1,10 +1,15 @@
export: clean wasm_exec
tinygo build -o ./html/wasm.wasm -target wasm ./export/wasm.go
tinygo build -o ./html/wasm.wasm -target wasm -no-debug ./export/wasm.go
cp ./export/wasm.js ./html/
cp ./export/index.html ./html/
callback: clean wasm_exec
tinygo build -o ./html/wasm.wasm -target wasm ./callback/wasm.go
cp ./callback/wasm.js ./html/
cp ./callback/index.html ./html/
main: clean wasm_exec
tinygo build -o ./html/wasm.wasm -target wasm ./main/main.go
tinygo build -o ./html/wasm.wasm -target wasm -no-debug ./main/main.go
cp ./main/index.html ./html/
wasm_exec:
+19
View File
@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Go WebAssembly</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="wasm_exec.js" defer></script>
<script src="wasm.js" defer></script>
</head>
<body>
<h1>WebAssembly</h1>
<p>Add two numbers, using WebAssembly:</p>
<input type="number" id="a" value="0" /> + <input type="number" id="b" value="0" /> = <input type="number" id="result" readonly />
</body>
</html>
+27
View File
@@ -0,0 +1,27 @@
package main
import (
"strconv"
"syscall/js"
)
var a, b int
func main() {
document := js.Global().Get("document")
document.Call("getElementById", "a").Set("oninput", updater(&a))
document.Call("getElementById", "b").Set("oninput", updater(&b))
update()
}
func updater(n *int) js.Func {
return js.FuncOf(func(this js.Value, args []js.Value) interface{} {
*n, _ = strconv.Atoi(this.Get("value").String())
update()
return nil
})
}
func update() {
js.Global().Get("document").Call("getElementById", "result").Set("value", a+b)
}
+26
View File
@@ -0,0 +1,26 @@
'use strict';
const WASM_URL = 'wasm.wasm';
var wasm;
function init() {
const go = new Go();
if ('instantiateStreaming' in WebAssembly) {
WebAssembly.instantiateStreaming(fetch(WASM_URL), go.importObject).then(function (obj) {
wasm = obj.instance;
go.run(wasm);
})
} else {
fetch(WASM_URL).then(resp =>
resp.arrayBuffer()
).then(bytes =>
WebAssembly.instantiate(bytes, go.importObject).then(function (obj) {
wasm = obj.instance;
go.run(wasm);
})
)
}
}
init();
+9 -9
View File
@@ -5,20 +5,20 @@ package machine
const CPU_FREQUENCY = 16000000
// LED on the Arduino
const LED = 13
const LED Pin = 13
// ADC on the Arduino
const (
ADC0 = 0
ADC1 = 1
ADC2 = 2
ADC3 = 3
ADC4 = 4 // Used by TWI for SDA
ADC5 = 5 // Used by TWI for SCL
ADC0 Pin = 0
ADC1 Pin = 1
ADC2 Pin = 2
ADC3 Pin = 3
ADC4 Pin = 4 // Used by TWI for SDA
ADC5 Pin = 5 // Used by TWI for SCL
)
// UART pins
const (
UART_TX_PIN = 1
UART_RX_PIN = 0
UART_TX_PIN Pin = 1
UART_RX_PIN Pin = 0
)
+4 -4
View File
@@ -17,7 +17,7 @@ const (
D8 = PB23
D9 = PA06
D10 = PA07
D11 = 0xff // does not seem to exist
D11 = NoPin // does not seem to exist
D12 = PA02
D13 = PA17 // PWM available
)
@@ -80,12 +80,12 @@ var (
I2C0 = I2C{Bus: sam.SERCOM5_I2CM,
SDA: SDA_PIN,
SCL: SCL_PIN,
PinMode: GPIO_SERCOM}
PinMode: PinSERCOM}
// internal device
I2C1 = I2C{Bus: sam.SERCOM1_I2CM,
SDA: SDA1_PIN,
SCL: SCL1_PIN,
PinMode: GPIO_SERCOM_ALT}
PinMode: PinSERCOMAlt}
)
// SPI pins (internal flash)
@@ -104,7 +104,7 @@ var (
const (
I2S_SCK_PIN = PA10
I2S_SD_PIN = PA08
I2S_WS_PIN = 0xff // no WS, instead uses SCK to sync
I2S_WS_PIN = NoPin // no WS, instead uses SCK to sync
)
// I2S on the Circuit Playground Express.
+1 -1
View File
@@ -3,5 +3,5 @@
package machine
const (
LED = 1
LED Pin = 1
)
+82
View File
@@ -0,0 +1,82 @@
// +build sam,atsamd21,feather_m0
package machine
import "device/sam"
// GPIO Pins
const (
D0 = PA11 // UART0 RX
D1 = PA10 // UART0 TX
D2 = NoPin // does not seem to exist
D3 = PA09
D4 = PA08
D5 = PA15 // PWM available
D6 = PA20 // PWM available
D7 = NoPin // does not seem to exist
D8 = PA06
D9 = PA07 // PWM available
D10 = PA18 // can be used for PWM or UART1 TX
D11 = PA16 // can be used for PWM or UART1 RX
D12 = PA19 // PWM available
D13 = PA17 // PWM available
)
// Analog pins
const (
A0 = PA02 // ADC/AIN[0]
A1 = PB08 // ADC/AIN[2]
A2 = PB09 // ADC/AIN[3]
A3 = PA04 // ADC/AIN[4]
A4 = PA05 // ADC/AIN[5]
A5 = PB02 // ADC/AIN[10]
)
const (
LED = D13
)
// UART0 aka USBCDC pins
const (
USBCDC_DM_PIN = PA24
USBCDC_DP_PIN = PA25
)
// UART1 pins
const (
UART_TX_PIN = D10
UART_RX_PIN = D11
)
// I2C pins
const (
SDA_PIN = PA22 // SDA: SERCOM3/PAD[0]
SCL_PIN = PA23 // SCL: SERCOM3/PAD[1]
)
// I2C on the Feather M0.
var (
I2C0 = I2C{Bus: sam.SERCOM3_I2CM,
SDA: SDA_PIN,
SCL: SCL_PIN,
PinMode: PinSERCOM}
)
// SPI pins
const (
SPI0_SCK_PIN = PB11 // SCK: SERCOM4/PAD[3]
SPI0_MOSI_PIN = PB10 // MOSI: SERCOM4/PAD[2]
SPI0_MISO_PIN = PA12 // MISO: SERCOM4/PAD[0]
)
// SPI on the Feather M0.
var (
SPI0 = SPI{Bus: sam.SERCOM4_SPI}
)
// I2S pins
const (
I2S_SCK_PIN = PA10
I2S_SD_PIN = PA08
I2S_WS_PIN = NoPin // TODO: figure out what this is on Feather M0.
)
+2 -2
View File
@@ -59,7 +59,7 @@ var (
I2C0 = I2C{Bus: sam.SERCOM3_I2CM,
SDA: SDA_PIN,
SCL: SCL_PIN,
PinMode: GPIO_SERCOM}
PinMode: PinSERCOM}
)
// SPI pins
@@ -78,7 +78,7 @@ var (
const (
I2S_SCK_PIN = PA10
I2S_SD_PIN = PA08
I2S_WS_PIN = 0xff // TODO: figure out what this is on ItsyBitsy M0.
I2S_WS_PIN = NoPin // TODO: figure out what this is on ItsyBitsy M0.
)
// I2S on the ItsyBitsy M0.
+42 -42
View File
@@ -7,70 +7,70 @@ const HasLowFrequencyCrystal = false
// Buttons on the micro:bit (A and B)
const (
BUTTON = BUTTONA
BUTTONA = 17
BUTTONB = 26
BUTTON Pin = BUTTONA
BUTTONA Pin = 17
BUTTONB Pin = 26
)
// UART pins
const (
UART_TX_PIN = 24
UART_RX_PIN = 25
UART_TX_PIN Pin = 24
UART_RX_PIN Pin = 25
)
// ADC pins
const (
ADC0 = 3 // P0 on the board
ADC1 = 2 // P1 on the board
ADC2 = 1 // P2 on the board
ADC0 Pin = 3 // P0 on the board
ADC1 Pin = 2 // P1 on the board
ADC2 Pin = 1 // P2 on the board
)
// I2C pins
const (
SDA_PIN = 30 // P20 on the board
SCL_PIN = 0 // P19 on the board
SDA_PIN Pin = 30 // P20 on the board
SCL_PIN Pin = 0 // P19 on the board
)
// SPI pins
const (
SPI0_SCK_PIN = 23 // P13 on the board
SPI0_MOSI_PIN = 21 // P15 on the board
SPI0_MISO_PIN = 22 // P14 on the board
SPI0_SCK_PIN Pin = 23 // P13 on the board
SPI0_MOSI_PIN Pin = 21 // P15 on the board
SPI0_MISO_PIN Pin = 22 // P14 on the board
)
// GPIO/Analog pins
const (
P0 = 3
P1 = 2
P2 = 1
P3 = 4
P4 = 5
P5 = 17
P6 = 12
P7 = 11
P8 = 18
P9 = 10
P10 = 6
P11 = 26
P12 = 20
P13 = 23
P14 = 22
P15 = 21
P16 = 16
P0 Pin = 3
P1 Pin = 2
P2 Pin = 1
P3 Pin = 4
P4 Pin = 5
P5 Pin = 17
P6 Pin = 12
P7 Pin = 11
P8 Pin = 18
P9 Pin = 10
P10 Pin = 6
P11 Pin = 26
P12 Pin = 20
P13 Pin = 23
P14 Pin = 22
P15 Pin = 21
P16 Pin = 16
)
// LED matrix pins
const (
LED_COL_1 = 4
LED_COL_2 = 5
LED_COL_3 = 6
LED_COL_4 = 7
LED_COL_5 = 8
LED_COL_6 = 9
LED_COL_7 = 10
LED_COL_8 = 11
LED_COL_9 = 12
LED_ROW_1 = 13
LED_ROW_2 = 14
LED_ROW_3 = 15
LED_COL_1 Pin = 4
LED_COL_2 Pin = 5
LED_COL_3 Pin = 6
LED_COL_4 Pin = 7
LED_COL_5 Pin = 8
LED_COL_6 Pin = 9
LED_COL_7 Pin = 10
LED_COL_8 Pin = 11
LED_COL_9 Pin = 12
LED_ROW_1 Pin = 13
LED_ROW_2 Pin = 14
LED_ROW_3 Pin = 15
)
+11 -11
View File
@@ -6,27 +6,27 @@ const HasLowFrequencyCrystal = true
// LEDs on the nrf52840-mdk (nRF52840 dev board)
const (
LED = LED_GREEN
LED_GREEN = 22
LED_RED = 23
LED_BLUE = 24
LED Pin = LED_GREEN
LED_GREEN Pin = 22
LED_RED Pin = 23
LED_BLUE Pin = 24
)
// UART pins
const (
UART_TX_PIN = 20
UART_RX_PIN = 19
UART_TX_PIN Pin = 20
UART_RX_PIN Pin = 19
)
// I2C pins (unused)
const (
SDA_PIN = 0xff
SCL_PIN = 0xff
SDA_PIN = NoPin
SCL_PIN = NoPin
)
// SPI pins (unused)
const (
SPI0_SCK_PIN = 0
SPI0_MOSI_PIN = 0
SPI0_MISO_PIN = 0
SPI0_SCK_PIN = NoPin
SPI0_MOSI_PIN = NoPin
SPI0_MISO_PIN = NoPin
)
+14 -14
View File
@@ -10,30 +10,30 @@ const HasLowFrequencyCrystal = true
// LED on the pca10031
const (
LED = LED_RED
LED1 = LED_RED
LED2 = LED_GREEN
LED3 = LED_BLUE
LED_RED = 21
LED_GREEN = 22
LED_BLUE = 23
LED Pin = LED_RED
LED1 Pin = LED_RED
LED2 Pin = LED_GREEN
LED3 Pin = LED_BLUE
LED_RED Pin = 21
LED_GREEN Pin = 22
LED_BLUE Pin = 23
)
// UART pins
const (
UART_TX_PIN = 9
UART_RX_PIN = 11
UART_TX_PIN Pin = 9
UART_RX_PIN Pin = 11
)
// I2C pins (disabled)
const (
SDA_PIN = 0xff
SCL_PIN = 0xff
SDA_PIN = NoPin
SCL_PIN = NoPin
)
// SPI pins (unused)
const (
SPI0_SCK_PIN = 0
SPI0_MOSI_PIN = 0
SPI0_MISO_PIN = 0
SPI0_SCK_PIN = NoPin
SPI0_MOSI_PIN = NoPin
SPI0_MISO_PIN = NoPin
)
+23 -23
View File
@@ -7,47 +7,47 @@ const HasLowFrequencyCrystal = true
// LEDs on the PCA10040 (nRF52832 dev board)
const (
LED = LED1
LED1 = 17
LED2 = 18
LED3 = 19
LED4 = 20
LED Pin = LED1
LED1 Pin = 17
LED2 Pin = 18
LED3 Pin = 19
LED4 Pin = 20
)
// Buttons on the PCA10040 (nRF52832 dev board)
const (
BUTTON = BUTTON1
BUTTON1 = 13
BUTTON2 = 14
BUTTON3 = 15
BUTTON4 = 16
BUTTON Pin = BUTTON1
BUTTON1 Pin = 13
BUTTON2 Pin = 14
BUTTON3 Pin = 15
BUTTON4 Pin = 16
)
// UART pins for NRF52840-DK
const (
UART_TX_PIN = 6
UART_RX_PIN = 8
UART_TX_PIN Pin = 6
UART_RX_PIN Pin = 8
)
// ADC pins
const (
ADC0 = 3
ADC1 = 4
ADC2 = 28
ADC3 = 29
ADC4 = 30
ADC5 = 31
ADC0 Pin = 3
ADC1 Pin = 4
ADC2 Pin = 28
ADC3 Pin = 29
ADC4 Pin = 30
ADC5 Pin = 31
)
// I2C pins
const (
SDA_PIN = 26
SCL_PIN = 27
SDA_PIN Pin = 26
SCL_PIN Pin = 27
)
// SPI pins
const (
SPI0_SCK_PIN = 25
SPI0_MOSI_PIN = 23
SPI0_MISO_PIN = 24
SPI0_SCK_PIN Pin = 25
SPI0_MOSI_PIN Pin = 23
SPI0_MISO_PIN Pin = 24
)
+23 -23
View File
@@ -6,47 +6,47 @@ const HasLowFrequencyCrystal = true
// LEDs on the pca10056
const (
LED = LED1
LED1 = 13
LED2 = 14
LED3 = 15
LED4 = 16
LED Pin = LED1
LED1 Pin = 13
LED2 Pin = 14
LED3 Pin = 15
LED4 Pin = 16
)
// Buttons on the pca10056
const (
BUTTON = BUTTON1
BUTTON1 = 11
BUTTON2 = 12
BUTTON3 = 24
BUTTON4 = 25
BUTTON Pin = BUTTON1
BUTTON1 Pin = 11
BUTTON2 Pin = 12
BUTTON3 Pin = 24
BUTTON4 Pin = 25
)
// UART pins
const (
UART_TX_PIN = 6
UART_RX_PIN = 8
UART_TX_PIN Pin = 6
UART_RX_PIN Pin = 8
)
// ADC pins
const (
ADC0 = 3
ADC1 = 4
ADC2 = 28
ADC3 = 29
ADC4 = 30
ADC5 = 31
ADC0 Pin = 3
ADC1 Pin = 4
ADC2 Pin = 28
ADC3 Pin = 29
ADC4 Pin = 30
ADC5 Pin = 31
)
// I2C pins
const (
SDA_PIN = 26 // P0.26
SCL_PIN = 27 // P0.27
SDA_PIN Pin = 26 // P0.26
SCL_PIN Pin = 27 // P0.27
)
// SPI pins
const (
SPI0_SCK_PIN = 47 // P1.15
SPI0_MOSI_PIN = 45 // P1.13
SPI0_MISO_PIN = 46 // P1.14
SPI0_SCK_PIN Pin = 47 // P1.15
SPI0_MOSI_PIN Pin = 45 // P1.13
SPI0_MISO_PIN Pin = 46 // P1.14
)
+17 -17
View File
@@ -6,37 +6,37 @@ const HasLowFrequencyCrystal = true
// LEDs on the reel board
const (
LED = LED1
LED1 = LED_YELLOW
LED2 = LED_RED
LED3 = LED_GREEN
LED4 = LED_BLUE
LED_RED = 11
LED_GREEN = 12
LED_BLUE = 41
LED_YELLOW = 13
LED Pin = LED1
LED1 Pin = LED_YELLOW
LED2 Pin = LED_RED
LED3 Pin = LED_GREEN
LED4 Pin = LED_BLUE
LED_RED Pin = 11
LED_GREEN Pin = 12
LED_BLUE Pin = 41
LED_YELLOW Pin = 13
)
// User "a" button on the reel board
const (
BUTTON = 7
BUTTON Pin = 7
)
// UART pins
const (
UART_TX_PIN = 6
UART_RX_PIN = 8
UART_TX_PIN Pin = 6
UART_RX_PIN Pin = 8
)
// I2C pins
const (
SDA_PIN = 26
SCL_PIN = 27
SDA_PIN Pin = 26
SCL_PIN Pin = 27
)
// SPI pins
const (
SPI0_SCK_PIN = 47
SPI0_MOSI_PIN = 45
SPI0_MISO_PIN = 46
SPI0_SCK_PIN Pin = 47
SPI0_MOSI_PIN Pin = 45
SPI0_MISO_PIN Pin = 46
)
+73
View File
@@ -0,0 +1,73 @@
// +build sam,atsamd21,trinket_m0
package machine
import "device/sam"
// GPIO Pins
const (
D0 = PA08 // PWM available
D1 = PA02
D2 = PA09 // PWM available
D3 = PA07 // PWM available / UART0 RX
D4 = PA06 // PWM available / UART0 TX
D13 = PA10 // LED
)
// Analog pins
const (
A0 = D1
A1 = D2
A2 = D0
A3 = D3
A4 = D4
)
const (
LED = D13
)
// UART0 aka USBCDC pins
const (
USBCDC_DM_PIN = PA24
USBCDC_DP_PIN = PA25
)
// UART1 pins
const (
UART_TX_PIN = D4
UART_RX_PIN = D3
)
// SPI pins
const (
SPI0_SCK_PIN = D3
SPI0_MOSI_PIN = D4
SPI0_MISO_PIN = D2
)
// SPI on the Trinket M0.
var (
SPI0 = SPI{Bus: sam.SERCOM0_SPI}
)
// I2C pins
const (
SDA_PIN = D0 // SDA
SCL_PIN = D2 // SCL
)
// I2C on the Trinket M0.
var (
I2C0 = I2C{Bus: sam.SERCOM2_I2CM,
SDA: SDA_PIN,
SCL: SCL_PIN,
PinMode: PinSERCOMAlt}
)
// I2S pins
const (
I2S_SCK_PIN = PA10
I2S_SD_PIN = PA08
I2S_WS_PIN = NoPin // TODO: figure out what this is on Trinket M0.
)
+3 -3
View File
@@ -41,9 +41,9 @@ const (
// All fields are optional and may not be required or used on a particular platform.
type I2SConfig struct {
SCK uint8
WS uint8
SD uint8
SCK Pin
WS Pin
SD Pin
Mode I2SMode
Standard I2SStandard
ClockSource I2SClockSource
+20 -9
View File
@@ -1,25 +1,36 @@
package machine
type GPIOConfig struct {
Mode GPIOMode
type PinConfig struct {
Mode PinMode
}
type GPIO struct {
Pin uint8
}
// Pin is a single pin on a chip, which may be connected to other hardware
// devices. It can either be used directly as GPIO pin or it can be used in
// other peripherals like ADC, I2C, etc.
type Pin int8
func (p GPIO) High() {
// NoPin explicitly indicates "not a pin". Use this pin if you want to leave one
// of the pins in a peripheral unconfigured (if supported by the hardware).
const NoPin = Pin(-1)
// High sets this GPIO pin to high, assuming it has been configured as an output
// pin. It is hardware dependent (and often undefined) what happens if you set a
// pin to high that is not configured as an output pin.
func (p Pin) High() {
p.Set(true)
}
func (p GPIO) Low() {
// Low sets this GPIO pin to low, assuming it has been configured as an output
// pin. It is hardware dependent (and often undefined) what happens if you set a
// pin to low that is not configured as an output pin.
func (p Pin) Low() {
p.Set(false)
}
type PWM struct {
Pin uint8
Pin Pin
}
type ADC struct {
Pin uint8
Pin Pin
}
+24 -24
View File
@@ -7,38 +7,38 @@ import (
)
// Configure sets the pin to input or output.
func (p GPIO) Configure(config GPIOConfig) {
if config.Mode == GPIO_OUTPUT { // set output bit
if p.Pin < 8 {
avr.DDRD.SetBits(1 << p.Pin)
func (p Pin) Configure(config PinConfig) {
if config.Mode == PinOutput { // set output bit
if p < 8 {
avr.DDRD.SetBits(1 << uint8(p))
} else {
avr.DDRB.SetBits(1 << (p.Pin - 8))
avr.DDRB.SetBits(1 << uint8(p-8))
}
} else { // configure input: clear output bit
if p.Pin < 8 {
avr.DDRD.ClearBits(1 << p.Pin)
if p < 8 {
avr.DDRD.ClearBits(1 << uint8(p))
} else {
avr.DDRB.ClearBits(1 << (p.Pin - 8))
avr.DDRB.ClearBits(1 << uint8(p-8))
}
}
}
// Get returns the current value of a GPIO pin.
func (p GPIO) Get() bool {
if p.Pin < 8 {
val := avr.PIND.Get() & (1 << p.Pin)
func (p Pin) Get() bool {
if p < 8 {
val := avr.PIND.Get() & (1 << uint8(p))
return (val > 0)
} else {
val := avr.PINB.Get() & (1 << (p.Pin - 8))
val := avr.PINB.Get() & (1 << uint8(p-8))
return (val > 0)
}
}
func (p GPIO) getPortMask() (*avr.Register8, uint8) {
if p.Pin < 8 {
return avr.PORTD, 1 << p.Pin
func (p Pin) getPortMask() (*avr.Register8, uint8) {
if p < 8 {
return avr.PORTD, 1 << uint8(p)
} else {
return avr.PORTB, 1 << (p.Pin - 8)
return avr.PORTB, 1 << uint8(p-8)
}
}
@@ -66,9 +66,9 @@ func InitPWM() {
// Configure configures a PWM pin for output.
func (pwm PWM) Configure() {
if pwm.Pin < 8 {
avr.DDRD.SetBits(1 << pwm.Pin)
avr.DDRD.SetBits(1 << uint8(pwm.Pin))
} else {
avr.DDRB.SetBits(1 << (pwm.Pin - 8))
avr.DDRB.SetBits(1 << uint8(pwm.Pin-8))
}
}
@@ -165,7 +165,7 @@ func (i2c I2C) start(address uint8, write bool) {
avr.TWCR.Set((avr.TWCR_TWINT | avr.TWCR_TWSTA | avr.TWCR_TWEN))
// Wait till start condition is transmitted.
for (avr.TWCR.Get() & avr.TWCR_TWINT) == 0 {
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
}
// Write 7-bit shifted peripheral address.
@@ -182,7 +182,7 @@ func (i2c I2C) stop() {
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWSTO)
// Wait for stop condition to be executed on bus.
for (avr.TWCR.Get() & avr.TWCR_TWSTO) == 0 {
for !avr.TWCR.HasBits(avr.TWCR_TWSTO) {
}
}
@@ -195,7 +195,7 @@ func (i2c I2C) writeByte(data byte) {
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT)
// Wait till data is transmitted.
for (avr.TWCR.Get() & avr.TWCR_TWINT) == 0 {
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
}
}
@@ -205,7 +205,7 @@ func (i2c I2C) readByte() byte {
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWEA)
// Wait till read request is transmitted.
for (avr.TWCR.Get() & avr.TWCR_TWINT) == 0 {
for !avr.TWCR.HasBits(avr.TWCR_TWINT) {
}
return byte(avr.TWDR.Get())
@@ -239,7 +239,7 @@ func (uart UART) Configure(config UARTConfig) {
// WriteByte writes a byte of data to the UART.
func (uart UART) WriteByte(c byte) error {
// Wait until UART buffer is not busy.
for (avr.UCSR0A.Get() & avr.UCSR0A_UDRE0) == 0 {
for !avr.UCSR0A.HasBits(avr.UCSR0A_UDRE0) {
}
avr.UDR0.Set(c) // send char
return nil
@@ -251,7 +251,7 @@ func handleUSART_RX() {
data := avr.UDR0.Get()
// Ensure no error.
if (avr.UCSR0A.Get() & (avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0)) == 0 {
if !avr.UCSR0A.HasBits(avr.UCSR0A_FE0 | avr.UCSR0A_DOR0 | avr.UCSR0A_UPE0) {
// Put data from UDR register into buffer.
UART0.Receive(byte(data))
}
File diff suppressed because it is too large Load Diff
+334
View File
@@ -0,0 +1,334 @@
// +build sam,atsamd21,atsamd21e18
// Peripheral abstraction layer for the atsamd21.
//
// Datasheet:
// http://ww1.microchip.com/downloads/en/DeviceDoc/SAMD21-Family-DataSheet-DS40001882D.pdf
//
package machine
import (
"device/sam"
)
// Return the register and mask to enable a given GPIO pin. This can be used to
// implement bit-banged drivers.
func (p Pin) PortMaskSet() (*uint32, uint32) {
return &sam.PORT.OUTSET0.Reg, 1 << uint8(p)
}
// Return the register and mask to disable a given port. This can be used to
// implement bit-banged drivers.
func (p Pin) PortMaskClear() (*uint32, uint32) {
return &sam.PORT.OUTCLR0.Reg, 1 << uint8(p)
}
// Set the pin to high or low.
// Warning: only use this on an output pin!
func (p Pin) Set(high bool) {
if high {
sam.PORT.OUTSET0.Set(1 << uint8(p))
} else {
sam.PORT.OUTCLR0.Set(1 << uint8(p))
}
}
// Get returns the current value of a GPIO pin.
func (p Pin) Get() bool {
return (sam.PORT.IN0.Get()>>uint8(p))&1 > 0
}
// Configure this pin with the given configuration.
func (p Pin) Configure(config PinConfig) {
switch config.Mode {
case PinOutput:
sam.PORT.DIRSET0.Set(1 << uint8(p))
// output is also set to input enable so pin can read back its own value
p.setPinCfg(sam.PORT_PINCFG0_INEN)
case PinInput:
sam.PORT.DIRCLR0.Set(1 << uint8(p))
p.setPinCfg(sam.PORT_PINCFG0_INEN)
case PinInputPulldown:
sam.PORT.DIRCLR0.Set(1 << uint8(p))
sam.PORT.OUTCLR0.Set(1 << uint8(p))
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
case PinInputPullup:
sam.PORT.DIRCLR0.Set(1 << uint8(p))
sam.PORT.OUTSET0.Set(1 << uint8(p))
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
case PinSERCOM:
if uint8(p)&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR | sam.PORT_PINCFG0_INEN)
case PinSERCOMAlt:
if uint8(p)&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR)
case PinCom:
if uint8(p)&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN)
case PinAnalog:
if uint8(p)&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR)
}
}
// getPMux returns the value for the correct PMUX register for this pin.
func (p Pin) getPMux() uint8 {
switch p >> 1 {
case 0:
return sam.PORT.PMUX0_0.Get()
case 1:
return sam.PORT.PMUX0_1.Get()
case 2:
return sam.PORT.PMUX0_2.Get()
case 3:
return sam.PORT.PMUX0_3.Get()
case 4:
return sam.PORT.PMUX0_4.Get()
case 5:
return sam.PORT.PMUX0_5.Get()
case 6:
return sam.PORT.PMUX0_6.Get()
case 7:
return sam.PORT.PMUX0_7.Get()
case 8:
return sam.PORT.PMUX0_8.Get()
case 9:
return sam.PORT.PMUX0_9.Get()
case 10:
return sam.PORT.PMUX0_10.Get()
case 11:
return sam.PORT.PMUX0_11.Get()
case 12:
return sam.PORT.PMUX0_12.Get()
case 13:
return sam.PORT.PMUX0_13.Get()
case 14:
return sam.PORT.PMUX0_14.Get()
case 15:
return sam.PORT.PMUX0_15.Get()
default:
return 0
}
}
// setPMux sets the value for the correct PMUX register for this pin.
func (p Pin) setPMux(val uint8) {
switch p >> 1 {
case 0:
sam.PORT.PMUX0_0.Set(val)
case 1:
sam.PORT.PMUX0_1.Set(val)
case 2:
sam.PORT.PMUX0_2.Set(val)
case 3:
sam.PORT.PMUX0_3.Set(val)
case 4:
sam.PORT.PMUX0_4.Set(val)
case 5:
sam.PORT.PMUX0_5.Set(val)
case 6:
sam.PORT.PMUX0_6.Set(val)
case 7:
sam.PORT.PMUX0_7.Set(val)
case 8:
sam.PORT.PMUX0_8.Set(val)
case 9:
sam.PORT.PMUX0_9.Set(val)
case 10:
sam.PORT.PMUX0_10.Set(val)
case 11:
sam.PORT.PMUX0_11.Set(val)
case 12:
sam.PORT.PMUX0_12.Set(val)
case 13:
sam.PORT.PMUX0_13.Set(val)
case 14:
sam.PORT.PMUX0_14.Set(val)
case 15:
sam.PORT.PMUX0_15.Set(val)
}
}
// getPinCfg returns the value for the correct PINCFG register for this pin.
func (p Pin) getPinCfg() uint8 {
switch p {
case 0:
return sam.PORT.PINCFG0_0.Get()
case 1:
return sam.PORT.PINCFG0_1.Get()
case 2:
return sam.PORT.PINCFG0_2.Get()
case 3:
return sam.PORT.PINCFG0_3.Get()
case 4:
return sam.PORT.PINCFG0_4.Get()
case 5:
return sam.PORT.PINCFG0_5.Get()
case 6:
return sam.PORT.PINCFG0_6.Get()
case 7:
return sam.PORT.PINCFG0_7.Get()
case 8:
return sam.PORT.PINCFG0_8.Get()
case 9:
return sam.PORT.PINCFG0_9.Get()
case 10:
return sam.PORT.PINCFG0_10.Get()
case 11:
return sam.PORT.PINCFG0_11.Get()
case 12:
return sam.PORT.PINCFG0_12.Get()
case 13:
return sam.PORT.PINCFG0_13.Get()
case 14:
return sam.PORT.PINCFG0_14.Get()
case 15:
return sam.PORT.PINCFG0_15.Get()
case 16:
return sam.PORT.PINCFG0_16.Get()
case 17:
return sam.PORT.PINCFG0_17.Get()
case 18:
return sam.PORT.PINCFG0_18.Get()
case 19:
return sam.PORT.PINCFG0_19.Get()
case 20:
return sam.PORT.PINCFG0_20.Get()
case 21:
return sam.PORT.PINCFG0_21.Get()
case 22:
return sam.PORT.PINCFG0_22.Get()
case 23:
return sam.PORT.PINCFG0_23.Get()
case 24:
return sam.PORT.PINCFG0_24.Get()
case 25:
return sam.PORT.PINCFG0_25.Get()
case 26:
return sam.PORT.PINCFG0_26.Get()
case 27:
return sam.PORT.PINCFG0_27.Get()
case 28:
return sam.PORT.PINCFG0_28.Get()
case 29:
return sam.PORT.PINCFG0_29.Get()
case 30:
return sam.PORT.PINCFG0_30.Get()
case 31:
return sam.PORT.PINCFG0_31.Get()
default:
return 0
}
}
// setPinCfg sets the value for the correct PINCFG register for this pin.
func (p Pin) setPinCfg(val uint8) {
switch p {
case 0:
sam.PORT.PINCFG0_0.Set(val)
case 1:
sam.PORT.PINCFG0_1.Set(val)
case 2:
sam.PORT.PINCFG0_2.Set(val)
case 3:
sam.PORT.PINCFG0_3.Set(val)
case 4:
sam.PORT.PINCFG0_4.Set(val)
case 5:
sam.PORT.PINCFG0_5.Set(val)
case 6:
sam.PORT.PINCFG0_6.Set(val)
case 7:
sam.PORT.PINCFG0_7.Set(val)
case 8:
sam.PORT.PINCFG0_8.Set(val)
case 9:
sam.PORT.PINCFG0_9.Set(val)
case 10:
sam.PORT.PINCFG0_10.Set(val)
case 11:
sam.PORT.PINCFG0_11.Set(val)
case 12:
sam.PORT.PINCFG0_12.Set(val)
case 13:
sam.PORT.PINCFG0_13.Set(val)
case 14:
sam.PORT.PINCFG0_14.Set(val)
case 15:
sam.PORT.PINCFG0_15.Set(val)
case 16:
sam.PORT.PINCFG0_16.Set(val)
case 17:
sam.PORT.PINCFG0_17.Set(val)
case 18:
sam.PORT.PINCFG0_18.Set(val)
case 19:
sam.PORT.PINCFG0_19.Set(val)
case 20:
sam.PORT.PINCFG0_20.Set(val)
case 21:
sam.PORT.PINCFG0_21.Set(val)
case 22:
sam.PORT.PINCFG0_22.Set(val)
case 23:
sam.PORT.PINCFG0_23.Set(val)
case 24:
sam.PORT.PINCFG0_24.Set(val)
case 25:
sam.PORT.PINCFG0_25.Set(val)
case 26:
sam.PORT.PINCFG0_26.Set(val)
case 27:
sam.PORT.PINCFG0_27.Set(val)
case 28:
sam.PORT.PINCFG0_28.Set(val)
case 29:
sam.PORT.PINCFG0_29.Set(val)
case 30:
sam.PORT.PINCFG0_30.Set(val)
case 31:
sam.PORT.PINCFG0_31.Set(val)
}
}
+569
View File
@@ -0,0 +1,569 @@
// +build sam,atsamd21,atsamd21g18
// Peripheral abstraction layer for the atsamd21.
//
// Datasheet:
// http://ww1.microchip.com/downloads/en/DeviceDoc/SAMD21-Family-DataSheet-DS40001882D.pdf
//
package machine
import (
"device/sam"
)
// Return the register and mask to enable a given GPIO pin. This can be used to
// implement bit-banged drivers.
func (p Pin) PortMaskSet() (*uint32, uint32) {
if p < 32 {
return &sam.PORT.OUTSET0.Reg, 1 << uint8(p)
} else {
return &sam.PORT.OUTSET1.Reg, 1 << uint8(p-32)
}
}
// Return the register and mask to disable a given port. This can be used to
// implement bit-banged drivers.
func (p Pin) PortMaskClear() (*uint32, uint32) {
if p < 32 {
return &sam.PORT.OUTCLR0.Reg, 1 << uint8(p)
} else {
return &sam.PORT.OUTCLR1.Reg, 1 << uint8(p-32)
}
}
// Set the pin to high or low.
// Warning: only use this on an output pin!
func (p Pin) Set(high bool) {
if p < 32 {
if high {
sam.PORT.OUTSET0.Set(1 << uint8(p))
} else {
sam.PORT.OUTCLR0.Set(1 << uint8(p))
}
} else {
if high {
sam.PORT.OUTSET1.Set(1 << uint8(p-32))
} else {
sam.PORT.OUTCLR1.Set(1 << uint8(p-32))
}
}
}
// Get returns the current value of a GPIO pin.
func (p Pin) Get() bool {
if p < 32 {
return (sam.PORT.IN0.Get()>>uint8(p))&1 > 0
} else {
return (sam.PORT.IN1.Get()>>(uint8(p)-32))&1 > 0
}
}
// Configure this pin with the given configuration.
func (p Pin) Configure(config PinConfig) {
switch config.Mode {
case PinOutput:
if p < 32 {
sam.PORT.DIRSET0.Set(1 << uint8(p))
// output is also set to input enable so pin can read back its own value
p.setPinCfg(sam.PORT_PINCFG0_INEN)
} else {
sam.PORT.DIRSET1.Set(1 << uint8(p-32))
// output is also set to input enable so pin can read back its own value
p.setPinCfg(sam.PORT_PINCFG0_INEN)
}
case PinInput:
if p < 32 {
sam.PORT.DIRCLR0.Set(1 << uint8(p))
p.setPinCfg(sam.PORT_PINCFG0_INEN)
} else {
sam.PORT.DIRCLR1.Set(1<<uint8(p) - 32)
p.setPinCfg(sam.PORT_PINCFG0_INEN)
}
case PinInputPulldown:
if p < 32 {
sam.PORT.DIRCLR0.Set(1 << uint8(p))
sam.PORT.OUTCLR0.Set(1 << uint8(p))
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
} else {
sam.PORT.DIRCLR1.Set(1<<uint8(p) - 32)
sam.PORT.OUTCLR1.Set(1<<uint8(p) - 32)
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
}
case PinInputPullup:
if p < 32 {
sam.PORT.DIRCLR0.Set(1 << uint8(p))
sam.PORT.OUTSET0.Set(1 << uint8(p))
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
} else {
sam.PORT.DIRCLR1.Set(1<<uint8(p) - 32)
sam.PORT.OUTSET1.Set(1<<uint8(p) - 32)
p.setPinCfg(sam.PORT_PINCFG0_INEN | sam.PORT_PINCFG0_PULLEN)
}
case PinSERCOM:
if p&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
p.setPMux(val | (uint8(PinSERCOM) << sam.PORT_PMUX0_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR | sam.PORT_PINCFG0_INEN)
case PinSERCOMAlt:
if p&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
p.setPMux(val | (uint8(PinSERCOMAlt) << sam.PORT_PMUX0_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR)
case PinCom:
if p&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
p.setPMux(val | (uint8(PinCom) << sam.PORT_PMUX0_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN)
case PinAnalog:
if p&1 > 0 {
// odd pin, so save the even pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXE_Msk
p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXO_Pos))
} else {
// even pin, so save the odd pins
val := p.getPMux() & sam.PORT_PMUX0_PMUXO_Msk
p.setPMux(val | (uint8(PinAnalog) << sam.PORT_PMUX0_PMUXE_Pos))
}
// enable port config
p.setPinCfg(sam.PORT_PINCFG0_PMUXEN | sam.PORT_PINCFG0_DRVSTR)
}
}
// getPMux returns the value for the correct PMUX register for this pin.
func (p Pin) getPMux() uint8 {
switch uint8(p) >> 1 {
case 0:
return sam.PORT.PMUX0_0.Get()
case 1:
return sam.PORT.PMUX0_1.Get()
case 2:
return sam.PORT.PMUX0_2.Get()
case 3:
return sam.PORT.PMUX0_3.Get()
case 4:
return sam.PORT.PMUX0_4.Get()
case 5:
return sam.PORT.PMUX0_5.Get()
case 6:
return sam.PORT.PMUX0_6.Get()
case 7:
return sam.PORT.PMUX0_7.Get()
case 8:
return sam.PORT.PMUX0_8.Get()
case 9:
return sam.PORT.PMUX0_9.Get()
case 10:
return sam.PORT.PMUX0_10.Get()
case 11:
return sam.PORT.PMUX0_11.Get()
case 12:
return sam.PORT.PMUX0_12.Get()
case 13:
return sam.PORT.PMUX0_13.Get()
case 14:
return sam.PORT.PMUX0_14.Get()
case 15:
return sam.PORT.PMUX0_15.Get()
case 16:
return uint8(sam.PORT.PMUX1_0.Get()>>0) & 0xff
case 17:
return uint8(sam.PORT.PMUX1_0.Get()>>8) & 0xff
case 18:
return uint8(sam.PORT.PMUX1_0.Get()>>16) & 0xff
case 19:
return uint8(sam.PORT.PMUX1_0.Get()>>24) & 0xff
case 20:
return uint8(sam.PORT.PMUX1_4.Get()>>0) & 0xff
case 21:
return uint8(sam.PORT.PMUX1_4.Get()>>8) & 0xff
case 22:
return uint8(sam.PORT.PMUX1_4.Get()>>16) & 0xff
case 23:
return uint8(sam.PORT.PMUX1_4.Get()>>24) & 0xff
case 24:
return uint8(sam.PORT.PMUX1_8.Get()>>0) & 0xff
case 25:
return uint8(sam.PORT.PMUX1_8.Get()>>8) & 0xff
case 26:
return uint8(sam.PORT.PMUX1_8.Get()>>16) & 0xff
case 27:
return uint8(sam.PORT.PMUX1_8.Get()>>24) & 0xff
case 28:
return uint8(sam.PORT.PMUX1_12.Get()>>0) & 0xff
case 29:
return uint8(sam.PORT.PMUX1_12.Get()>>8) & 0xff
case 30:
return uint8(sam.PORT.PMUX1_12.Get()>>16) & 0xff
case 31:
return uint8(sam.PORT.PMUX1_12.Get()>>24) & 0xff
default:
return 0
}
}
// setPMux sets the value for the correct PMUX register for this pin.
func (p Pin) setPMux(val uint8) {
switch uint8(p) >> 1 {
case 0:
sam.PORT.PMUX0_0.Set(val)
case 1:
sam.PORT.PMUX0_1.Set(val)
case 2:
sam.PORT.PMUX0_2.Set(val)
case 3:
sam.PORT.PMUX0_3.Set(val)
case 4:
sam.PORT.PMUX0_4.Set(val)
case 5:
sam.PORT.PMUX0_5.Set(val)
case 6:
sam.PORT.PMUX0_6.Set(val)
case 7:
sam.PORT.PMUX0_7.Set(val)
case 8:
sam.PORT.PMUX0_8.Set(val)
case 9:
sam.PORT.PMUX0_9.Set(val)
case 10:
sam.PORT.PMUX0_10.Set(val)
case 11:
sam.PORT.PMUX0_11.Set(val)
case 12:
sam.PORT.PMUX0_12.Set(val)
case 13:
sam.PORT.PMUX0_13.Set(val)
case 14:
sam.PORT.PMUX0_14.Set(val)
case 15:
sam.PORT.PMUX0_15.Set(val)
case 16:
sam.PORT.PMUX1_0.Set(sam.PORT.PMUX1_0.Get()&^(0xff<<0) | (uint32(val) << 0))
case 17:
sam.PORT.PMUX1_0.Set(sam.PORT.PMUX1_0.Get()&^(0xff<<8) | (uint32(val) << 8))
case 18:
sam.PORT.PMUX1_0.Set(sam.PORT.PMUX1_0.Get()&^(0xff<<16) | (uint32(val) << 16))
case 19:
sam.PORT.PMUX1_0.Set(sam.PORT.PMUX1_0.Get()&^(0xff<<24) | (uint32(val) << 24))
case 20:
sam.PORT.PMUX1_4.Set(sam.PORT.PMUX1_4.Get()&^(0xff<<0) | (uint32(val) << 0))
case 21:
sam.PORT.PMUX1_4.Set(sam.PORT.PMUX1_4.Get()&^(0xff<<8) | (uint32(val) << 8))
case 22:
sam.PORT.PMUX1_4.Set(sam.PORT.PMUX1_4.Get()&^(0xff<<16) | (uint32(val) << 16))
case 23:
sam.PORT.PMUX1_4.Set(sam.PORT.PMUX1_4.Get()&^(0xff<<24) | (uint32(val) << 24))
case 24:
sam.PORT.PMUX1_8.Set(sam.PORT.PMUX1_8.Get()&^(0xff<<0) | (uint32(val) << 0))
case 25:
sam.PORT.PMUX1_8.Set(sam.PORT.PMUX1_8.Get()&^(0xff<<8) | (uint32(val) << 8))
case 26:
sam.PORT.PMUX1_8.Set(sam.PORT.PMUX1_8.Get()&^(0xff<<16) | (uint32(val) << 16))
case 27:
sam.PORT.PMUX1_8.Set(sam.PORT.PMUX1_8.Get()&^(0xff<<24) | (uint32(val) << 24))
case 28:
sam.PORT.PMUX1_12.Set(sam.PORT.PMUX1_12.Get()&^(0xff<<0) | (uint32(val) << 0))
case 29:
sam.PORT.PMUX1_12.Set(sam.PORT.PMUX1_12.Get()&^(0xff<<8) | (uint32(val) << 8))
case 30:
sam.PORT.PMUX1_12.Set(sam.PORT.PMUX1_12.Get()&^(0xff<<16) | (uint32(val) << 16))
case 31:
sam.PORT.PMUX1_12.Set(sam.PORT.PMUX1_12.Get()&^(0xff<<24) | (uint32(val) << 24))
}
}
// getPinCfg returns the value for the correct PINCFG register for this pin.
func (p Pin) getPinCfg() uint8 {
switch p {
case 0:
return sam.PORT.PINCFG0_0.Get()
case 1:
return sam.PORT.PINCFG0_1.Get()
case 2:
return sam.PORT.PINCFG0_2.Get()
case 3:
return sam.PORT.PINCFG0_3.Get()
case 4:
return sam.PORT.PINCFG0_4.Get()
case 5:
return sam.PORT.PINCFG0_5.Get()
case 6:
return sam.PORT.PINCFG0_6.Get()
case 7:
return sam.PORT.PINCFG0_7.Get()
case 8:
return sam.PORT.PINCFG0_8.Get()
case 9:
return sam.PORT.PINCFG0_9.Get()
case 10:
return sam.PORT.PINCFG0_10.Get()
case 11:
return sam.PORT.PINCFG0_11.Get()
case 12:
return sam.PORT.PINCFG0_12.Get()
case 13:
return sam.PORT.PINCFG0_13.Get()
case 14:
return sam.PORT.PINCFG0_14.Get()
case 15:
return sam.PORT.PINCFG0_15.Get()
case 16:
return sam.PORT.PINCFG0_16.Get()
case 17:
return sam.PORT.PINCFG0_17.Get()
case 18:
return sam.PORT.PINCFG0_18.Get()
case 19:
return sam.PORT.PINCFG0_19.Get()
case 20:
return sam.PORT.PINCFG0_20.Get()
case 21:
return sam.PORT.PINCFG0_21.Get()
case 22:
return sam.PORT.PINCFG0_22.Get()
case 23:
return sam.PORT.PINCFG0_23.Get()
case 24:
return sam.PORT.PINCFG0_24.Get()
case 25:
return sam.PORT.PINCFG0_25.Get()
case 26:
return sam.PORT.PINCFG0_26.Get()
case 27:
return sam.PORT.PINCFG0_27.Get()
case 28:
return sam.PORT.PINCFG0_28.Get()
case 29:
return sam.PORT.PINCFG0_29.Get()
case 30:
return sam.PORT.PINCFG0_30.Get()
case 31:
return sam.PORT.PINCFG0_31.Get()
case 32: // PB00
return uint8(sam.PORT.PINCFG1_0.Get()>>0) & 0xff
case 33: // PB01
return uint8(sam.PORT.PINCFG1_0.Get()>>8) & 0xff
case 34: // PB02
return uint8(sam.PORT.PINCFG1_0.Get()>>16) & 0xff
case 35: // PB03
return uint8(sam.PORT.PINCFG1_0.Get()>>24) & 0xff
case 37: // PB04
return uint8(sam.PORT.PINCFG1_4.Get()>>0) & 0xff
case 38: // PB05
return uint8(sam.PORT.PINCFG1_4.Get()>>8) & 0xff
case 39: // PB06
return uint8(sam.PORT.PINCFG1_4.Get()>>16) & 0xff
case 40: // PB07
return uint8(sam.PORT.PINCFG1_4.Get()>>24) & 0xff
case 41: // PB08
return uint8(sam.PORT.PINCFG1_8.Get()>>0) & 0xff
case 42: // PB09
return uint8(sam.PORT.PINCFG1_8.Get()>>8) & 0xff
case 43: // PB10
return uint8(sam.PORT.PINCFG1_8.Get()>>16) & 0xff
case 44: // PB11
return uint8(sam.PORT.PINCFG1_8.Get()>>24) & 0xff
case 45: // PB12
return uint8(sam.PORT.PINCFG1_12.Get()>>0) & 0xff
case 46: // PB13
return uint8(sam.PORT.PINCFG1_12.Get()>>8) & 0xff
case 47: // PB14
return uint8(sam.PORT.PINCFG1_12.Get()>>16) & 0xff
case 48: // PB15
return uint8(sam.PORT.PINCFG1_12.Get()>>24) & 0xff
case 49: // PB16
return uint8(sam.PORT.PINCFG1_16.Get()>>0) & 0xff
case 50: // PB17
return uint8(sam.PORT.PINCFG1_16.Get()>>8) & 0xff
case 51: // PB18
return uint8(sam.PORT.PINCFG1_16.Get()>>16) & 0xff
case 52: // PB19
return uint8(sam.PORT.PINCFG1_16.Get()>>24) & 0xff
case 53: // PB20
return uint8(sam.PORT.PINCFG1_20.Get()>>0) & 0xff
case 54: // PB21
return uint8(sam.PORT.PINCFG1_20.Get()>>8) & 0xff
case 55: // PB22
return uint8(sam.PORT.PINCFG1_20.Get()>>16) & 0xff
case 56: // PB23
return uint8(sam.PORT.PINCFG1_20.Get()>>24) & 0xff
case 57: // PB24
return uint8(sam.PORT.PINCFG1_24.Get()>>0) & 0xff
case 58: // PB25
return uint8(sam.PORT.PINCFG1_24.Get()>>8) & 0xff
case 59: // PB26
return uint8(sam.PORT.PINCFG1_24.Get()>>16) & 0xff
case 60: // PB27
return uint8(sam.PORT.PINCFG1_24.Get()>>24) & 0xff
case 61: // PB28
return uint8(sam.PORT.PINCFG1_28.Get()>>0) & 0xff
case 62: // PB29
return uint8(sam.PORT.PINCFG1_28.Get()>>8) & 0xff
case 63: // PB30
return uint8(sam.PORT.PINCFG1_28.Get()>>16) & 0xff
case 64: // PB31
return uint8(sam.PORT.PINCFG1_28.Get()>>24) & 0xff
default:
return 0
}
}
// setPinCfg sets the value for the correct PINCFG register for this pin.
func (p Pin) setPinCfg(val uint8) {
switch p {
case 0:
sam.PORT.PINCFG0_0.Set(val)
case 1:
sam.PORT.PINCFG0_1.Set(val)
case 2:
sam.PORT.PINCFG0_2.Set(val)
case 3:
sam.PORT.PINCFG0_3.Set(val)
case 4:
sam.PORT.PINCFG0_4.Set(val)
case 5:
sam.PORT.PINCFG0_5.Set(val)
case 6:
sam.PORT.PINCFG0_6.Set(val)
case 7:
sam.PORT.PINCFG0_7.Set(val)
case 8:
sam.PORT.PINCFG0_8.Set(val)
case 9:
sam.PORT.PINCFG0_9.Set(val)
case 10:
sam.PORT.PINCFG0_10.Set(val)
case 11:
sam.PORT.PINCFG0_11.Set(val)
case 12:
sam.PORT.PINCFG0_12.Set(val)
case 13:
sam.PORT.PINCFG0_13.Set(val)
case 14:
sam.PORT.PINCFG0_14.Set(val)
case 15:
sam.PORT.PINCFG0_15.Set(val)
case 16:
sam.PORT.PINCFG0_16.Set(val)
case 17:
sam.PORT.PINCFG0_17.Set(val)
case 18:
sam.PORT.PINCFG0_18.Set(val)
case 19:
sam.PORT.PINCFG0_19.Set(val)
case 20:
sam.PORT.PINCFG0_20.Set(val)
case 21:
sam.PORT.PINCFG0_21.Set(val)
case 22:
sam.PORT.PINCFG0_22.Set(val)
case 23:
sam.PORT.PINCFG0_23.Set(val)
case 24:
sam.PORT.PINCFG0_24.Set(val)
case 25:
sam.PORT.PINCFG0_25.Set(val)
case 26:
sam.PORT.PINCFG0_26.Set(val)
case 27:
sam.PORT.PINCFG0_27.Set(val)
case 28:
sam.PORT.PINCFG0_28.Set(val)
case 29:
sam.PORT.PINCFG0_29.Set(val)
case 30:
sam.PORT.PINCFG0_30.Set(val)
case 31:
sam.PORT.PINCFG0_31.Set(val)
case 32: // PB00
sam.PORT.PINCFG1_0.Set(sam.PORT.PINCFG1_0.Get()&^(0xff<<0) | (uint32(val) << 0))
case 33: // PB01
sam.PORT.PINCFG1_0.Set(sam.PORT.PINCFG1_0.Get()&^(0xff<<8) | (uint32(val) << 8))
case 34: // PB02
sam.PORT.PINCFG1_0.Set(sam.PORT.PINCFG1_0.Get()&^(0xff<<16) | (uint32(val) << 16))
case 35: // PB03
sam.PORT.PINCFG1_0.Set(sam.PORT.PINCFG1_0.Get()&^(0xff<<24) | (uint32(val) << 24))
case 36: // PB04
sam.PORT.PINCFG1_4.Set(sam.PORT.PINCFG1_4.Get()&^(0xff<<0) | (uint32(val) << 0))
case 37: // PB05
sam.PORT.PINCFG1_4.Set(sam.PORT.PINCFG1_4.Get()&^(0xff<<8) | (uint32(val) << 8))
case 38: // PB06
sam.PORT.PINCFG1_4.Set(sam.PORT.PINCFG1_4.Get()&^(0xff<<16) | (uint32(val) << 16))
case 39: // PB07
sam.PORT.PINCFG1_4.Set(sam.PORT.PINCFG1_4.Get()&^(0xff<<24) | (uint32(val) << 24))
case 40: // PB08
sam.PORT.PINCFG1_8.Set(sam.PORT.PINCFG1_8.Get()&^(0xff<<0) | (uint32(val) << 0))
case 41: // PB09
sam.PORT.PINCFG1_8.Set(sam.PORT.PINCFG1_8.Get()&^(0xff<<8) | (uint32(val) << 8))
case 42: // PB10
sam.PORT.PINCFG1_8.Set(sam.PORT.PINCFG1_8.Get()&^(0xff<<16) | (uint32(val) << 16))
case 43: // PB11
sam.PORT.PINCFG1_8.Set(sam.PORT.PINCFG1_8.Get()&^(0xff<<24) | (uint32(val) << 24))
case 44: // PB12
sam.PORT.PINCFG1_12.Set(sam.PORT.PINCFG1_12.Get()&^(0xff<<0) | (uint32(val) << 0))
case 45: // PB13
sam.PORT.PINCFG1_12.Set(sam.PORT.PINCFG1_12.Get()&^(0xff<<8) | (uint32(val) << 8))
case 46: // PB14
sam.PORT.PINCFG1_12.Set(sam.PORT.PINCFG1_12.Get()&^(0xff<<16) | (uint32(val) << 16))
case 47: // PB15
sam.PORT.PINCFG1_12.Set(sam.PORT.PINCFG1_12.Get()&^(0xff<<24) | (uint32(val) << 24))
case 48: // PB16
sam.PORT.PINCFG1_16.Set(sam.PORT.PINCFG1_16.Get()&^(0xff<<0) | (uint32(val) << 0))
case 49: // PB17
sam.PORT.PINCFG1_16.Set(sam.PORT.PINCFG1_16.Get()&^(0xff<<8) | (uint32(val) << 8))
case 50: // PB18
sam.PORT.PINCFG1_16.Set(sam.PORT.PINCFG1_16.Get()&^(0xff<<16) | (uint32(val) << 16))
case 51: // PB19
sam.PORT.PINCFG1_16.Set(sam.PORT.PINCFG1_16.Get()&^(0xff<<24) | (uint32(val) << 24))
case 52: // PB20
sam.PORT.PINCFG1_20.Set(sam.PORT.PINCFG1_20.Get()&^(0xff<<0) | (uint32(val) << 0))
case 53: // PB21
sam.PORT.PINCFG1_20.Set(sam.PORT.PINCFG1_20.Get()&^(0xff<<8) | (uint32(val) << 8))
case 54: // PB22
sam.PORT.PINCFG1_20.Set(sam.PORT.PINCFG1_20.Get()&^(0xff<<16) | (uint32(val) << 16))
case 55: // PB23
sam.PORT.PINCFG1_20.Set(sam.PORT.PINCFG1_20.Get()&^(0xff<<24) | (uint32(val) << 24))
case 56: // PB24
sam.PORT.PINCFG1_24.Set(sam.PORT.PINCFG1_24.Get()&^(0xff<<0) | (uint32(val) << 0))
case 57: // PB25
sam.PORT.PINCFG1_24.Set(sam.PORT.PINCFG1_24.Get()&^(0xff<<8) | (uint32(val) << 8))
case 58: // PB26
sam.PORT.PINCFG1_24.Set(sam.PORT.PINCFG1_24.Get()&^(0xff<<16) | (uint32(val) << 16))
case 59: // PB27
sam.PORT.PINCFG1_24.Set(sam.PORT.PINCFG1_24.Get()&^(0xff<<24) | (uint32(val) << 24))
case 60: // PB28
sam.PORT.PINCFG1_28.Set(sam.PORT.PINCFG1_28.Get()&^(0xff<<0) | (uint32(val) << 0))
case 61: // PB29
sam.PORT.PINCFG1_28.Set(sam.PORT.PINCFG1_28.Get()&^(0xff<<8) | (uint32(val) << 8))
case 62: // PB30
sam.PORT.PINCFG1_28.Set(sam.PORT.PINCFG1_28.Get()&^(0xff<<16) | (uint32(val) << 16))
case 63: // PB31
sam.PORT.PINCFG1_28.Set(sam.PORT.PINCFG1_28.Get()&^(0xff<<24) | (uint32(val) << 24))
}
}
+8 -8
View File
@@ -7,21 +7,21 @@ import (
)
// Configure sets the pin to input or output.
func (p GPIO) Configure(config GPIOConfig) {
if config.Mode == GPIO_OUTPUT { // set output bit
avr.DDRB.SetBits(1 << p.Pin)
func (p Pin) Configure(config PinConfig) {
if config.Mode == PinOutput { // set output bit
avr.DDRB.SetBits(1 << uint8(p))
} else { // configure input: clear output bit
avr.DDRB.ClearBits(1 << p.Pin)
avr.DDRB.ClearBits(1 << uint8(p))
}
}
func (p GPIO) getPortMask() (*avr.Register8, uint8) {
return avr.PORTB, 1 << p.Pin
func (p Pin) getPortMask() (*avr.Register8, uint8) {
return avr.PORTB, 1 << uint8(p)
}
// Get returns the current value of a GPIO pin.
func (p GPIO) Get() bool {
val := avr.PINB.Get() & (1 << p.Pin)
func (p Pin) Get() bool {
val := avr.PINB.Get() & (1 << uint8(p))
return (val > 0)
}
+8 -8
View File
@@ -6,15 +6,15 @@ import (
"device/avr"
)
type GPIOMode uint8
type PinMode uint8
const (
GPIO_INPUT = iota
GPIO_OUTPUT
PinInput PinMode = iota
PinOutput
)
// Set changes the value of the GPIO pin. The pin must be configured as output.
func (p GPIO) Set(value bool) {
func (p Pin) Set(value bool) {
if value { // set bits
port, mask := p.PortMaskSet()
port.Set(mask)
@@ -30,7 +30,7 @@ func (p GPIO) Set(value bool) {
// Warning: there are no separate pin set/clear registers on the AVR. The
// returned mask is only valid as long as no other pin in the same port has been
// changed.
func (p GPIO) PortMaskSet() (*avr.Register8, uint8) {
func (p Pin) PortMaskSet() (*avr.Register8, uint8) {
port, mask := p.getPortMask()
return port, port.Get() | mask
}
@@ -41,7 +41,7 @@ func (p GPIO) PortMaskSet() (*avr.Register8, uint8) {
// Warning: there are no separate pin set/clear registers on the AVR. The
// returned mask is only valid as long as no other pin in the same port has been
// changed.
func (p GPIO) PortMaskClear() (*avr.Register8, uint8) {
func (p Pin) PortMaskClear() (*avr.Register8, uint8) {
port, mask := p.getPortMask()
return port, port.Get() &^ mask
}
@@ -68,13 +68,13 @@ func (a ADC) Get() uint16 {
// set the ADLAR bit (left-adjusted result) to get a value scaled to 16
// bits. This has the same effect as shifting the return value left by 6
// bits.
avr.ADMUX.Set(avr.ADMUX_REFS0 | avr.ADMUX_ADLAR | (a.Pin & 0x07))
avr.ADMUX.Set(avr.ADMUX_REFS0 | avr.ADMUX_ADLAR | (uint8(a.Pin) & 0x07))
// start the conversion
avr.ADCSRA.SetBits(avr.ADCSRA_ADSC)
// ADSC is cleared when the conversion finishes
for ok := true; ok; ok = (avr.ADCSRA.Get() & avr.ADCSRA_ADSC) > 0 {
for ok := true; ok; ok = avr.ADCSRA.HasBits(avr.ADCSRA_ADSC) {
}
return uint16(avr.ADCL.Get()) | uint16(avr.ADCH.Get())<<8
+16 -16
View File
@@ -4,37 +4,37 @@ package machine
// Dummy machine package, filled with no-ops.
type GPIOMode uint8
type PinMode uint8
const (
GPIO_INPUT = iota
GPIO_OUTPUT
PinInput PinMode = iota
PinOutput
)
// Fake LED numbers, for testing.
const (
LED = LED1
LED1 = 0
LED2 = 0
LED3 = 0
LED4 = 0
LED Pin = LED1
LED1 Pin = 0
LED2 Pin = 0
LED3 Pin = 0
LED4 Pin = 0
)
// Fake button numbers, for testing.
const (
BUTTON = BUTTON1
BUTTON1 = 0
BUTTON2 = 0
BUTTON3 = 0
BUTTON4 = 0
BUTTON Pin = BUTTON1
BUTTON1 Pin = 0
BUTTON2 Pin = 0
BUTTON3 Pin = 0
BUTTON4 Pin = 0
)
func (p GPIO) Configure(config GPIOConfig) {
func (p Pin) Configure(config PinConfig) {
}
func (p GPIO) Set(value bool) {
func (p Pin) Set(value bool) {
}
func (p GPIO) Get() bool {
func (p Pin) Get() bool {
return false
}
+66 -66
View File
@@ -7,51 +7,51 @@ import (
"device/nrf"
)
type GPIOMode uint8
type PinMode uint8
const (
GPIO_INPUT = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos)
GPIO_INPUT_PULLUP = GPIO_INPUT | (nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos)
GPIO_INPUT_PULLDOWN = GPIO_INPUT | (nrf.GPIO_PIN_CNF_PULL_Pulldown << nrf.GPIO_PIN_CNF_PULL_Pos)
GPIO_OUTPUT = (nrf.GPIO_PIN_CNF_DIR_Output << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Disconnect << 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)
PinInputPulldown PinMode = PinOutput | (nrf.GPIO_PIN_CNF_PULL_Pulldown << nrf.GPIO_PIN_CNF_PULL_Pos)
PinOutput PinMode = (nrf.GPIO_PIN_CNF_DIR_Output << nrf.GPIO_PIN_CNF_DIR_Pos) | (nrf.GPIO_PIN_CNF_INPUT_Disconnect << nrf.GPIO_PIN_CNF_INPUT_Pos)
)
// Configure this pin with the given configuration.
func (p GPIO) Configure(config GPIOConfig) {
func (p Pin) Configure(config PinConfig) {
cfg := config.Mode | nrf.GPIO_PIN_CNF_DRIVE_S0S1 | nrf.GPIO_PIN_CNF_SENSE_Disabled
port, pin := p.getPortPin()
port.PIN_CNF[pin] = nrf.RegValue(cfg)
port.PIN_CNF[pin].Set(uint32(cfg))
}
// Set the pin to high or low.
// Warning: only use this on an output pin!
func (p GPIO) Set(high bool) {
func (p Pin) Set(high bool) {
port, pin := p.getPortPin()
if high {
port.OUTSET = 1 << pin
port.OUTSET.Set(1 << pin)
} else {
port.OUTCLR = 1 << pin
port.OUTCLR.Set(1 << pin)
}
}
// Return the register and mask to enable a given GPIO pin. This can be used to
// implement bit-banged drivers.
func (p GPIO) PortMaskSet() (*uint32, uint32) {
func (p Pin) PortMaskSet() (*uint32, uint32) {
port, pin := p.getPortPin()
return (*uint32)(&port.OUTSET), 1 << pin
return &port.OUTSET.Reg, 1 << pin
}
// Return the register and mask to disable a given port. This can be used to
// implement bit-banged drivers.
func (p GPIO) PortMaskClear() (*uint32, uint32) {
func (p Pin) PortMaskClear() (*uint32, uint32) {
port, pin := p.getPortPin()
return (*uint32)(&port.OUTCLR), 1 << pin
return &port.OUTCLR.Reg, 1 << pin
}
// Get returns the current value of a GPIO pin.
func (p GPIO) Get() bool {
func (p Pin) Get() bool {
port, pin := p.getPortPin()
return (port.IN>>pin)&1 != 0
return (port.IN.Get()>>pin)&1 != 0
}
// UART on the NRF.
@@ -77,10 +77,10 @@ func (uart UART) Configure(config UARTConfig) {
// Set TX and RX pins from board.
uart.setPins(UART_TX_PIN, UART_RX_PIN)
nrf.UART0.ENABLE = nrf.UART_ENABLE_ENABLE_Enabled
nrf.UART0.TASKS_STARTTX = 1
nrf.UART0.TASKS_STARTRX = 1
nrf.UART0.INTENSET = nrf.UART_INTENSET_RXDRDY_Msk
nrf.UART0.ENABLE.Set(nrf.UART_ENABLE_ENABLE_Enabled)
nrf.UART0.TASKS_STARTTX.Set(1)
nrf.UART0.TASKS_STARTRX.Set(1)
nrf.UART0.INTENSET.Set(nrf.UART_INTENSET_RXDRDY_Msk)
// Enable RX IRQ.
arm.SetPriority(nrf.IRQ_UART0, 0xc0) // low priority
@@ -99,22 +99,22 @@ func (uart UART) SetBaudRate(br uint32) {
// https://devzone.nordicsemi.com/f/nordic-q-a/391/uart-baudrate-register-values/2046#2046
rate := uint32((uint64(br/400)*uint64(400*0xffffffff/16000000) + 0x800) & 0xffffff000)
nrf.UART0.BAUDRATE = nrf.RegValue(rate)
nrf.UART0.BAUDRATE.Set(rate)
}
// WriteByte writes a byte of data to the UART.
func (uart UART) WriteByte(c byte) error {
nrf.UART0.EVENTS_TXDRDY = 0
nrf.UART0.TXD = nrf.RegValue(c)
for nrf.UART0.EVENTS_TXDRDY == 0 {
nrf.UART0.EVENTS_TXDRDY.Set(0)
nrf.UART0.TXD.Set(uint32(c))
for nrf.UART0.EVENTS_TXDRDY.Get() == 0 {
}
return nil
}
func (uart UART) handleInterrupt() {
if nrf.UART0.EVENTS_RXDRDY != 0 {
uart.Receive(byte(nrf.UART0.RXD))
nrf.UART0.EVENTS_RXDRDY = 0x0
if nrf.UART0.EVENTS_RXDRDY.Get() != 0 {
uart.Receive(byte(nrf.UART0.RXD.Get()))
nrf.UART0.EVENTS_RXDRDY.Set(0x0)
}
}
@@ -132,8 +132,8 @@ var (
// I2CConfig is used to store config info for I2C.
type I2CConfig struct {
Frequency uint32
SCL uint8
SDA uint8
SCL Pin
SDA Pin
}
// Configure is intended to setup the I2C interface.
@@ -149,27 +149,27 @@ func (i2c I2C) Configure(config I2CConfig) {
}
// do config
sclPort, sclPin := GPIO{config.SCL}.getPortPin()
sclPort.PIN_CNF[sclPin] = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
sclPort, sclPin := config.SCL.getPortPin()
sclPort.PIN_CNF[sclPin].Set((nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
(nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) |
(nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) |
(nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) |
(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos)
(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos))
sdaPort, sdaPin := GPIO{config.SDA}.getPortPin()
sdaPort.PIN_CNF[sdaPin] = (nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
sdaPort, sdaPin := config.SDA.getPortPin()
sdaPort.PIN_CNF[sdaPin].Set((nrf.GPIO_PIN_CNF_DIR_Input << nrf.GPIO_PIN_CNF_DIR_Pos) |
(nrf.GPIO_PIN_CNF_INPUT_Connect << nrf.GPIO_PIN_CNF_INPUT_Pos) |
(nrf.GPIO_PIN_CNF_PULL_Pullup << nrf.GPIO_PIN_CNF_PULL_Pos) |
(nrf.GPIO_PIN_CNF_DRIVE_S0D1 << nrf.GPIO_PIN_CNF_DRIVE_Pos) |
(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos)
(nrf.GPIO_PIN_CNF_SENSE_Disabled << nrf.GPIO_PIN_CNF_SENSE_Pos))
if config.Frequency == TWI_FREQ_400KHZ {
i2c.Bus.FREQUENCY = nrf.TWI_FREQUENCY_FREQUENCY_K400
i2c.Bus.FREQUENCY.Set(nrf.TWI_FREQUENCY_FREQUENCY_K400)
} else {
i2c.Bus.FREQUENCY = nrf.TWI_FREQUENCY_FREQUENCY_K100
i2c.Bus.FREQUENCY.Set(nrf.TWI_FREQUENCY_FREQUENCY_K100)
}
i2c.Bus.ENABLE = nrf.TWI_ENABLE_ENABLE_Enabled
i2c.Bus.ENABLE.Set(nrf.TWI_ENABLE_ENABLE_Enabled)
i2c.setPins(config.SCL, config.SDA)
}
@@ -177,28 +177,28 @@ func (i2c I2C) Configure(config I2CConfig) {
// It clocks out the given address, writes the bytes in w, reads back len(r)
// bytes and stores them in r, and generates a stop condition on the bus.
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
i2c.Bus.ADDRESS = nrf.RegValue(addr)
i2c.Bus.ADDRESS.Set(uint32(addr))
if len(w) != 0 {
i2c.Bus.TASKS_STARTTX = 1 // start transmission for writing
i2c.Bus.TASKS_STARTTX.Set(1) // start transmission for writing
for _, b := range w {
i2c.writeByte(b)
}
}
if len(r) != 0 {
// To trigger suspend task when a byte is received
i2c.Bus.SHORTS = nrf.TWI_SHORTS_BB_SUSPEND
i2c.Bus.TASKS_STARTRX = 1 // re-start transmission for reading
for i := range r { // read each char
i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND)
i2c.Bus.TASKS_STARTRX.Set(1) // re-start transmission for reading
for i := range r { // read each char
if i+1 == len(r) {
// To trigger stop task when last byte is received, set before resume task.
i2c.Bus.SHORTS = nrf.TWI_SHORTS_BB_STOP
i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_STOP)
}
i2c.Bus.TASKS_RESUME = 1 // re-start transmission for reading
i2c.Bus.TASKS_RESUME.Set(1) // re-start transmission for reading
r[i] = i2c.readByte()
}
}
i2c.signalStop()
i2c.Bus.SHORTS = nrf.TWI_SHORTS_BB_SUSPEND_Disabled
i2c.Bus.SHORTS.Set(nrf.TWI_SHORTS_BB_SUSPEND_Disabled)
return nil
}
@@ -206,26 +206,26 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
// it must generate a stop condition after the next character is retrieved when
// reading.
func (i2c I2C) signalStop() {
i2c.Bus.TASKS_STOP = 1
for i2c.Bus.EVENTS_STOPPED == 0 {
i2c.Bus.TASKS_STOP.Set(1)
for i2c.Bus.EVENTS_STOPPED.Get() == 0 {
}
i2c.Bus.EVENTS_STOPPED = 0
i2c.Bus.EVENTS_STOPPED.Set(0)
}
// writeByte writes a single byte to the I2C bus.
func (i2c I2C) writeByte(data byte) {
i2c.Bus.TXD = nrf.RegValue(data)
for i2c.Bus.EVENTS_TXDSENT == 0 {
i2c.Bus.TXD.Set(uint32(data))
for i2c.Bus.EVENTS_TXDSENT.Get() == 0 {
}
i2c.Bus.EVENTS_TXDSENT = 0
i2c.Bus.EVENTS_TXDSENT.Set(0)
}
// readByte reads a single byte from the I2C bus.
func (i2c I2C) readByte() byte {
for i2c.Bus.EVENTS_RXDREADY == 0 {
for i2c.Bus.EVENTS_RXDREADY.Get() == 0 {
}
i2c.Bus.EVENTS_RXDREADY = 0
return byte(i2c.Bus.RXD)
i2c.Bus.EVENTS_RXDREADY.Set(0)
return byte(i2c.Bus.RXD.Get())
}
// SPI on the NRF.
@@ -242,9 +242,9 @@ var (
// SPIConfig is used to store config info for SPI.
type SPIConfig struct {
Frequency uint32
SCK uint8
MOSI uint8
MISO uint8
SCK Pin
MOSI Pin
MISO Pin
LSBFirst bool
Mode uint8
}
@@ -252,7 +252,7 @@ type SPIConfig struct {
// Configure is intended to setup the SPI interface.
func (spi SPI) Configure(config SPIConfig) {
// Disable bus to configure it
spi.Bus.ENABLE = nrf.SPI_ENABLE_ENABLE_Disabled
spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Disabled)
// set frequency
var freq uint32
@@ -275,7 +275,7 @@ func (spi SPI) Configure(config SPIConfig) {
default:
freq = nrf.SPI_FREQUENCY_FREQUENCY_K500
}
spi.Bus.FREQUENCY = nrf.RegValue(freq)
spi.Bus.FREQUENCY.Set(freq)
var conf uint32
@@ -302,22 +302,22 @@ func (spi SPI) Configure(config SPIConfig) {
conf &^= (nrf.SPI_CONFIG_CPOL_ActiveHigh << nrf.SPI_CONFIG_CPOL_Pos)
conf &^= (nrf.SPI_CONFIG_CPHA_Leading << nrf.SPI_CONFIG_CPHA_Pos)
}
spi.Bus.CONFIG = nrf.RegValue(conf)
spi.Bus.CONFIG.Set(conf)
// set pins
spi.setPins(config.SCK, config.MOSI, config.MISO)
// Re-enable bus now that it is configured.
spi.Bus.ENABLE = nrf.SPI_ENABLE_ENABLE_Enabled
spi.Bus.ENABLE.Set(nrf.SPI_ENABLE_ENABLE_Enabled)
}
// Transfer writes/reads a single byte using the SPI interface.
func (spi SPI) Transfer(w byte) (byte, error) {
spi.Bus.TXD = nrf.RegValue(w)
for spi.Bus.EVENTS_READY == 0 {
spi.Bus.TXD.Set(uint32(w))
for spi.Bus.EVENTS_READY.Get() == 0 {
}
r := spi.Bus.RXD
spi.Bus.EVENTS_READY = 0
r := spi.Bus.RXD.Get()
spi.Bus.EVENTS_READY.Set(0)
// TODO: handle SPI errors
return byte(r), nil
+12 -12
View File
@@ -9,13 +9,13 @@ import (
const CPU_FREQUENCY = 16000000
// Get peripheral and pin number for this GPIO pin.
func (p GPIO) getPortPin() (*nrf.GPIO_Type, uint8) {
return nrf.GPIO, p.Pin
func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
return nrf.GPIO, uint32(p)
}
func (uart UART) setPins(tx, rx uint32) {
nrf.UART0.PSELTXD = nrf.RegValue(tx)
nrf.UART0.PSELRXD = nrf.RegValue(rx)
func (uart UART) setPins(tx, rx Pin) {
nrf.UART0.PSELTXD.Set(uint32(tx))
nrf.UART0.PSELRXD.Set(uint32(rx))
}
//go:export UART0_IRQHandler
@@ -23,13 +23,13 @@ func handleUART0() {
UART0.handleInterrupt()
}
func (i2c I2C) setPins(scl, sda uint8) {
i2c.Bus.PSELSCL = nrf.RegValue(scl)
i2c.Bus.PSELSDA = nrf.RegValue(sda)
func (i2c I2C) setPins(scl, sda Pin) {
i2c.Bus.PSELSCL.Set(uint32(scl))
i2c.Bus.PSELSDA.Set(uint32(sda))
}
// SPI
func (spi SPI) setPins(sck, mosi, miso uint8) {
func (spi SPI) setPins(sck, mosi, miso Pin) {
if sck == 0 {
sck = SPI0_SCK_PIN
}
@@ -39,7 +39,7 @@ func (spi SPI) setPins(sck, mosi, miso uint8) {
if miso == 0 {
miso = SPI0_MISO_PIN
}
spi.Bus.PSELSCK = nrf.RegValue(sck)
spi.Bus.PSELMOSI = nrf.RegValue(mosi)
spi.Bus.PSELMISO = nrf.RegValue(miso)
spi.Bus.PSELSCK.Set(uint32(sck))
spi.Bus.PSELMOSI.Set(uint32(mosi))
spi.Bus.PSELMISO.Set(uint32(miso))
}
+47 -47
View File
@@ -10,13 +10,13 @@ import (
const CPU_FREQUENCY = 64000000
// Get peripheral and pin number for this GPIO pin.
func (p GPIO) getPortPin() (*nrf.GPIO_Type, uint8) {
return nrf.P0, p.Pin
func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
return nrf.P0, uint32(p)
}
func (uart UART) setPins(tx, rx uint32) {
nrf.UART0.PSELTXD = nrf.RegValue(tx)
nrf.UART0.PSELRXD = nrf.RegValue(rx)
func (uart UART) setPins(tx, rx Pin) {
nrf.UART0.PSELTXD.Set(uint32(tx))
nrf.UART0.PSELRXD.Set(uint32(rx))
}
//go:export UARTE0_UART0_IRQHandler
@@ -24,13 +24,13 @@ func handleUART0() {
UART0.handleInterrupt()
}
func (i2c I2C) setPins(scl, sda uint8) {
i2c.Bus.PSELSCL = nrf.RegValue(scl)
i2c.Bus.PSELSDA = nrf.RegValue(sda)
func (i2c I2C) setPins(scl, sda Pin) {
i2c.Bus.PSELSCL.Set(uint32(scl))
i2c.Bus.PSELSDA.Set(uint32(sda))
}
// SPI
func (spi SPI) setPins(sck, mosi, miso uint8) {
func (spi SPI) setPins(sck, mosi, miso Pin) {
if sck == 0 {
sck = SPI0_SCK_PIN
}
@@ -40,9 +40,9 @@ func (spi SPI) setPins(sck, mosi, miso uint8) {
if miso == 0 {
miso = SPI0_MISO_PIN
}
spi.Bus.PSEL.SCK = nrf.RegValue(sck)
spi.Bus.PSEL.MOSI = nrf.RegValue(mosi)
spi.Bus.PSEL.MISO = nrf.RegValue(miso)
spi.Bus.PSEL.SCK.Set(uint32(sck))
spi.Bus.PSEL.MOSI.Set(uint32(mosi))
spi.Bus.PSEL.MISO.Set(uint32(miso))
}
// InitADC initializes the registers needed for ADC.
@@ -89,53 +89,53 @@ func (a ADC) Get() uint16 {
return 0
}
nrf.SAADC.RESOLUTION = nrf.SAADC_RESOLUTION_VAL_12bit
nrf.SAADC.RESOLUTION.Set(nrf.SAADC_RESOLUTION_VAL_12bit)
// Enable ADC.
nrf.SAADC.ENABLE = (nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
for i := 0; i < 8; i++ {
nrf.SAADC.CH[i].PSELN = nrf.SAADC_CH_PSELP_PSELP_NC
nrf.SAADC.CH[i].PSELP = nrf.SAADC_CH_PSELP_PSELP_NC
nrf.SAADC.CH[i].PSELN.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
nrf.SAADC.CH[i].PSELP.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
}
// Configure ADC.
nrf.SAADC.CH[0].CONFIG = ((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
nrf.SAADC.CH[0].CONFIG.Set(((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESN_Pos) & nrf.SAADC_CH_CONFIG_RESN_Msk) |
((nrf.SAADC_CH_CONFIG_GAIN_Gain1_5 << nrf.SAADC_CH_CONFIG_GAIN_Pos) & nrf.SAADC_CH_CONFIG_GAIN_Msk) |
((nrf.SAADC_CH_CONFIG_REFSEL_Internal << nrf.SAADC_CH_CONFIG_REFSEL_Pos) & nrf.SAADC_CH_CONFIG_REFSEL_Msk) |
((nrf.SAADC_CH_CONFIG_TACQ_3us << nrf.SAADC_CH_CONFIG_TACQ_Pos) & nrf.SAADC_CH_CONFIG_TACQ_Msk) |
((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk)
((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk))
// Set pin to read.
nrf.SAADC.CH[0].PSELN = nrf.RegValue(pwmPin)
nrf.SAADC.CH[0].PSELP = nrf.RegValue(pwmPin)
nrf.SAADC.CH[0].PSELN.Set(pwmPin)
nrf.SAADC.CH[0].PSELP.Set(pwmPin)
// Destination for sample result.
nrf.SAADC.RESULT.PTR = nrf.RegValue(uintptr(unsafe.Pointer(&value)))
nrf.SAADC.RESULT.MAXCNT = 1 // One sample
nrf.SAADC.RESULT.PTR.Set(uint32(uintptr(unsafe.Pointer(&value))))
nrf.SAADC.RESULT.MAXCNT.Set(1) // One sample
// Start tasks.
nrf.SAADC.TASKS_START = 1
for nrf.SAADC.EVENTS_STARTED == 0 {
nrf.SAADC.TASKS_START.Set(1)
for nrf.SAADC.EVENTS_STARTED.Get() == 0 {
}
nrf.SAADC.EVENTS_STARTED = 0x00
nrf.SAADC.EVENTS_STARTED.Set(0x00)
// Start the sample task.
nrf.SAADC.TASKS_SAMPLE = 1
nrf.SAADC.TASKS_SAMPLE.Set(1)
// Wait until the sample task is done.
for nrf.SAADC.EVENTS_END == 0 {
for nrf.SAADC.EVENTS_END.Get() == 0 {
}
nrf.SAADC.EVENTS_END = 0x00
nrf.SAADC.EVENTS_END.Set(0x00)
// Stop the ADC
nrf.SAADC.TASKS_STOP = 1
for nrf.SAADC.EVENTS_STOPPED == 0 {
nrf.SAADC.TASKS_STOP.Set(1)
for nrf.SAADC.EVENTS_STOPPED.Get() == 0 {
}
nrf.SAADC.EVENTS_STOPPED = 0
nrf.SAADC.EVENTS_STOPPED.Set(0)
// Disable the ADC.
nrf.SAADC.ENABLE = (nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
if value < 0 {
value = 0
@@ -170,21 +170,21 @@ func (pwm PWM) Set(value uint16) {
p := pwms[i]
p.PSEL.OUT[0] = nrf.RegValue(pwm.Pin)
p.PSEL.OUT[1] = nrf.RegValue(pwm.Pin)
p.PSEL.OUT[2] = nrf.RegValue(pwm.Pin)
p.PSEL.OUT[3] = nrf.RegValue(pwm.Pin)
p.ENABLE = (nrf.PWM_ENABLE_ENABLE_Enabled << nrf.PWM_ENABLE_ENABLE_Pos)
p.PRESCALER = nrf.PWM_PRESCALER_PRESCALER_DIV_2
p.MODE = nrf.PWM_MODE_UPDOWN_Up
p.COUNTERTOP = 16384 // frequency
p.LOOP = 0
p.DECODER = (nrf.PWM_DECODER_LOAD_Common << nrf.PWM_DECODER_LOAD_Pos) | (nrf.PWM_DECODER_MODE_RefreshCount << nrf.PWM_DECODER_MODE_Pos)
p.SEQ[0].PTR = nrf.RegValue(uintptr(unsafe.Pointer(&pwmChannelSequence[i])))
p.SEQ[0].CNT = 1
p.SEQ[0].REFRESH = 1
p.SEQ[0].ENDDELAY = 0
p.TASKS_SEQSTART[0] = 1
p.PSEL.OUT[0].Set(uint32(pwm.Pin))
p.PSEL.OUT[1].Set(uint32(pwm.Pin))
p.PSEL.OUT[2].Set(uint32(pwm.Pin))
p.PSEL.OUT[3].Set(uint32(pwm.Pin))
p.ENABLE.Set(nrf.PWM_ENABLE_ENABLE_Enabled << nrf.PWM_ENABLE_ENABLE_Pos)
p.PRESCALER.Set(nrf.PWM_PRESCALER_PRESCALER_DIV_2)
p.MODE.Set(nrf.PWM_MODE_UPDOWN_Up)
p.COUNTERTOP.Set(16384) // frequency
p.LOOP.Set(0)
p.DECODER.Set((nrf.PWM_DECODER_LOAD_Common << nrf.PWM_DECODER_LOAD_Pos) | (nrf.PWM_DECODER_MODE_RefreshCount << nrf.PWM_DECODER_MODE_Pos))
p.SEQ[0].PTR.Set(uint32(uintptr(unsafe.Pointer(&pwmChannelSequence[i]))))
p.SEQ[0].CNT.Set(1)
p.SEQ[0].REFRESH.Set(1)
p.SEQ[0].ENDDELAY.Set(0)
p.TASKS_SEQSTART[0].Set(1)
break
}
+49 -49
View File
@@ -10,17 +10,17 @@ import (
const CPU_FREQUENCY = 64000000
// Get peripheral and pin number for this GPIO pin.
func (p GPIO) getPortPin() (*nrf.GPIO_Type, uint8) {
if p.Pin >= 32 {
return nrf.P1, p.Pin - 32
func (p Pin) getPortPin() (*nrf.GPIO_Type, uint32) {
if p >= 32 {
return nrf.P1, uint32(p - 32)
} else {
return nrf.P0, p.Pin
return nrf.P0, uint32(p)
}
}
func (uart UART) setPins(tx, rx uint32) {
nrf.UART0.PSEL.TXD = nrf.RegValue(tx)
nrf.UART0.PSEL.RXD = nrf.RegValue(rx)
func (uart UART) setPins(tx, rx Pin) {
nrf.UART0.PSEL.TXD.Set(uint32(tx))
nrf.UART0.PSEL.RXD.Set(uint32(rx))
}
//go:export UARTE0_UART0_IRQHandler
@@ -28,13 +28,13 @@ func handleUART0() {
UART0.handleInterrupt()
}
func (i2c I2C) setPins(scl, sda uint8) {
i2c.Bus.PSEL.SCL = nrf.RegValue(scl)
i2c.Bus.PSEL.SDA = nrf.RegValue(sda)
func (i2c I2C) setPins(scl, sda Pin) {
i2c.Bus.PSEL.SCL.Set(uint32(scl))
i2c.Bus.PSEL.SDA.Set(uint32(sda))
}
// SPI
func (spi SPI) setPins(sck, mosi, miso uint8) {
func (spi SPI) setPins(sck, mosi, miso Pin) {
if sck == 0 {
sck = SPI0_SCK_PIN
}
@@ -44,9 +44,9 @@ func (spi SPI) setPins(sck, mosi, miso uint8) {
if miso == 0 {
miso = SPI0_MISO_PIN
}
spi.Bus.PSEL.SCK = nrf.RegValue(sck)
spi.Bus.PSEL.MOSI = nrf.RegValue(mosi)
spi.Bus.PSEL.MISO = nrf.RegValue(miso)
spi.Bus.PSEL.SCK.Set(uint32(sck))
spi.Bus.PSEL.MOSI.Set(uint32(mosi))
spi.Bus.PSEL.MISO.Set(uint32(miso))
}
// InitADC initializes the registers needed for ADC.
@@ -93,53 +93,53 @@ func (a ADC) Get() uint16 {
return 0
}
nrf.SAADC.RESOLUTION = nrf.SAADC_RESOLUTION_VAL_12bit
nrf.SAADC.RESOLUTION.Set(nrf.SAADC_RESOLUTION_VAL_12bit)
// Enable ADC.
nrf.SAADC.ENABLE = (nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Enabled << nrf.SAADC_ENABLE_ENABLE_Pos)
for i := 0; i < 8; i++ {
nrf.SAADC.CH[i].PSELN = nrf.SAADC_CH_PSELP_PSELP_NC
nrf.SAADC.CH[i].PSELP = nrf.SAADC_CH_PSELP_PSELP_NC
nrf.SAADC.CH[i].PSELN.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
nrf.SAADC.CH[i].PSELP.Set(nrf.SAADC_CH_PSELP_PSELP_NC)
}
// Configure ADC.
nrf.SAADC.CH[0].CONFIG = ((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
nrf.SAADC.CH[0].CONFIG.Set(((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESP_Pos) & nrf.SAADC_CH_CONFIG_RESP_Msk) |
((nrf.SAADC_CH_CONFIG_RESP_Bypass << nrf.SAADC_CH_CONFIG_RESN_Pos) & nrf.SAADC_CH_CONFIG_RESN_Msk) |
((nrf.SAADC_CH_CONFIG_GAIN_Gain1_5 << nrf.SAADC_CH_CONFIG_GAIN_Pos) & nrf.SAADC_CH_CONFIG_GAIN_Msk) |
((nrf.SAADC_CH_CONFIG_REFSEL_Internal << nrf.SAADC_CH_CONFIG_REFSEL_Pos) & nrf.SAADC_CH_CONFIG_REFSEL_Msk) |
((nrf.SAADC_CH_CONFIG_TACQ_3us << nrf.SAADC_CH_CONFIG_TACQ_Pos) & nrf.SAADC_CH_CONFIG_TACQ_Msk) |
((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk)
((nrf.SAADC_CH_CONFIG_MODE_SE << nrf.SAADC_CH_CONFIG_MODE_Pos) & nrf.SAADC_CH_CONFIG_MODE_Msk))
// Set pin to read.
nrf.SAADC.CH[0].PSELN = nrf.RegValue(pwmPin)
nrf.SAADC.CH[0].PSELP = nrf.RegValue(pwmPin)
nrf.SAADC.CH[0].PSELN.Set(pwmPin)
nrf.SAADC.CH[0].PSELP.Set(pwmPin)
// Destination for sample result.
nrf.SAADC.RESULT.PTR = nrf.RegValue(uintptr(unsafe.Pointer(&value)))
nrf.SAADC.RESULT.MAXCNT = 1 // One sample
nrf.SAADC.RESULT.PTR.Set(uint32(uintptr(unsafe.Pointer(&value))))
nrf.SAADC.RESULT.MAXCNT.Set(1) // One sample
// Start tasks.
nrf.SAADC.TASKS_START = 1
for nrf.SAADC.EVENTS_STARTED == 0 {
nrf.SAADC.TASKS_START.Set(1)
for nrf.SAADC.EVENTS_STARTED.Get() == 0 {
}
nrf.SAADC.EVENTS_STARTED = 0x00
nrf.SAADC.EVENTS_STARTED.Set(0x00)
// Start the sample task.
nrf.SAADC.TASKS_SAMPLE = 1
nrf.SAADC.TASKS_SAMPLE.Set(1)
// Wait until the sample task is done.
for nrf.SAADC.EVENTS_END == 0 {
for nrf.SAADC.EVENTS_END.Get() == 0 {
}
nrf.SAADC.EVENTS_END = 0x00
nrf.SAADC.EVENTS_END.Set(0x00)
// Stop the ADC
nrf.SAADC.TASKS_STOP = 1
for nrf.SAADC.EVENTS_STOPPED == 0 {
nrf.SAADC.TASKS_STOP.Set(1)
for nrf.SAADC.EVENTS_STOPPED.Get() == 0 {
}
nrf.SAADC.EVENTS_STOPPED = 0
nrf.SAADC.EVENTS_STOPPED.Set(0)
// Disable the ADC.
nrf.SAADC.ENABLE = (nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
nrf.SAADC.ENABLE.Set(nrf.SAADC_ENABLE_ENABLE_Disabled << nrf.SAADC_ENABLE_ENABLE_Pos)
if value < 0 {
value = 0
@@ -174,21 +174,21 @@ func (pwm PWM) Set(value uint16) {
p := pwms[i]
p.PSEL.OUT[0] = nrf.RegValue(pwm.Pin)
p.PSEL.OUT[1] = nrf.RegValue(pwm.Pin)
p.PSEL.OUT[2] = nrf.RegValue(pwm.Pin)
p.PSEL.OUT[3] = nrf.RegValue(pwm.Pin)
p.ENABLE = (nrf.PWM_ENABLE_ENABLE_Enabled << nrf.PWM_ENABLE_ENABLE_Pos)
p.PRESCALER = nrf.PWM_PRESCALER_PRESCALER_DIV_2
p.MODE = nrf.PWM_MODE_UPDOWN_Up
p.COUNTERTOP = 16384 // frequency
p.LOOP = 0
p.DECODER = (nrf.PWM_DECODER_LOAD_Common << nrf.PWM_DECODER_LOAD_Pos) | (nrf.PWM_DECODER_MODE_RefreshCount << nrf.PWM_DECODER_MODE_Pos)
p.SEQ[0].PTR = nrf.RegValue(uintptr(unsafe.Pointer(&pwmChannelSequence[i])))
p.SEQ[0].CNT = 1
p.SEQ[0].REFRESH = 1
p.SEQ[0].ENDDELAY = 0
p.TASKS_SEQSTART[0] = 1
p.PSEL.OUT[0].Set(uint32(pwm.Pin))
p.PSEL.OUT[1].Set(uint32(pwm.Pin))
p.PSEL.OUT[2].Set(uint32(pwm.Pin))
p.PSEL.OUT[3].Set(uint32(pwm.Pin))
p.ENABLE.Set(nrf.PWM_ENABLE_ENABLE_Enabled << nrf.PWM_ENABLE_ENABLE_Pos)
p.PRESCALER.Set(nrf.PWM_PRESCALER_PRESCALER_DIV_2)
p.MODE.Set(nrf.PWM_MODE_UPDOWN_Up)
p.COUNTERTOP.Set(16384) // frequency
p.LOOP.Set(0)
p.DECODER.Set((nrf.PWM_DECODER_LOAD_Common << nrf.PWM_DECODER_LOAD_Pos) | (nrf.PWM_DECODER_MODE_RefreshCount << nrf.PWM_DECODER_MODE_Pos))
p.SEQ[0].PTR.Set(uint32(uintptr(unsafe.Pointer(&pwmChannelSequence[i]))))
p.SEQ[0].CNT.Set(1)
p.SEQ[0].REFRESH.Set(1)
p.SEQ[0].ENDDELAY.Set(0)
p.TASKS_SEQSTART[0].Set(1)
break
}
+2 -2
View File
@@ -4,10 +4,10 @@ package machine
// Peripheral abstraction layer for the stm32.
type GPIOMode uint8
type PinMode uint8
const (
portA = iota * 16
portA Pin = iota * 16
portB
portC
portD
+131 -126
View File
@@ -13,25 +13,25 @@ import (
const CPU_FREQUENCY = 72000000
const (
GPIO_INPUT = 0 // Input mode
GPIO_OUTPUT_10MHz = 1 // Output mode, max speed 10MHz
GPIO_OUTPUT_2MHz = 2 // Output mode, max speed 2MHz
GPIO_OUTPUT_50MHz = 3 // Output mode, max speed 50MHz
GPIO_OUTPUT = GPIO_OUTPUT_2MHz
PinInput PinMode = 0 // Input mode
PinOutput10MHz PinMode = 1 // Output mode, max speed 10MHz
PinOutput2MHz PinMode = 2 // Output mode, max speed 2MHz
PinOutput50MHz PinMode = 3 // Output mode, max speed 50MHz
PinOutput PinMode = PinOutput2MHz
GPIO_INPUT_MODE_ANALOG = 0 // Input analog mode
GPIO_INPUT_MODE_FLOATING = 4 // Input floating mode
GPIO_INPUT_MODE_PULL_UP_DOWN = 8 // Input pull up/down mode
GPIO_INPUT_MODE_RESERVED = 12 // Input mode (reserved)
PinInputModeAnalog PinMode = 0 // Input analog mode
PinInputModeFloating PinMode = 4 // Input floating mode
PinInputModePullUpDown PinMode = 8 // Input pull up/down mode
PinInputModeReserved PinMode = 12 // Input mode (reserved)
GPIO_OUTPUT_MODE_GP_PUSH_PULL = 0 // Output mode general purpose push/pull
GPIO_OUTPUT_MODE_GP_OPEN_DRAIN = 4 // Output mode general purpose open drain
GPIO_OUTPUT_MODE_ALT_PUSH_PULL = 8 // Output mode alt. purpose push/pull
GPIO_OUTPUT_MODE_ALT_OPEN_DRAIN = 12 // Output mode alt. purpose open drain
PinOutputModeGPPushPull PinMode = 0 // Output mode general purpose push/pull
PinOutputModeGPOpenDrain PinMode = 4 // Output mode general purpose open drain
PinOutputModeAltPushPull PinMode = 8 // Output mode alt. purpose push/pull
PinOutputModeAltOpenDrain PinMode = 12 // Output mode alt. purpose open drain
)
func (p GPIO) getPort() *stm32.GPIO_Type {
switch p.Pin / 16 {
func (p Pin) getPort() *stm32.GPIO_Type {
switch p / 16 {
case 0:
return stm32.GPIOA
case 1:
@@ -52,50 +52,50 @@ func (p GPIO) getPort() *stm32.GPIO_Type {
}
// enableClock enables the clock for this desired GPIO port.
func (p GPIO) enableClock() {
switch p.Pin / 16 {
func (p Pin) enableClock() {
switch p / 16 {
case 0:
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPAEN
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPAEN)
case 1:
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPBEN
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPBEN)
case 2:
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPCEN
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPCEN)
case 3:
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPDEN
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPDEN)
case 4:
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPEEN
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPEEN)
case 5:
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPFEN
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPFEN)
case 6:
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_IOPGEN
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_IOPGEN)
default:
panic("machine: unknown port")
}
}
// Configure this pin with the given configuration.
func (p GPIO) Configure(config GPIOConfig) {
func (p Pin) Configure(config PinConfig) {
// Configure the GPIO pin.
p.enableClock()
port := p.getPort()
pin := p.Pin % 16
pos := p.Pin % 8 * 4
pin := uint8(p) % 16
pos := uint8(p) % 8 * 4
if pin < 8 {
port.CRL = stm32.RegValue((uint32(port.CRL) &^ (0xf << pos)) | (uint32(config.Mode) << pos))
port.CRL.Set((uint32(port.CRL.Get()) &^ (0xf << pos)) | (uint32(config.Mode) << pos))
} else {
port.CRH = stm32.RegValue((uint32(port.CRH) &^ (0xf << pos)) | (uint32(config.Mode) << pos))
port.CRH.Set((uint32(port.CRH.Get()) &^ (0xf << pos)) | (uint32(config.Mode) << pos))
}
}
// Set the pin to high or low.
// Warning: only use this on an output pin!
func (p GPIO) Set(high bool) {
func (p Pin) Set(high bool) {
port := p.getPort()
pin := p.Pin % 16
pin := uint8(p) % 16
if high {
port.BSRR = 1 << pin
port.BSRR.Set(1 << pin)
} else {
port.BSRR = 1 << (pin + 16)
port.BSRR.Set(1 << (pin + 16))
}
}
@@ -122,24 +122,24 @@ func (uart UART) Configure(config UARTConfig) {
switch config.TX {
case PB6:
// use alternate TX/RX pins PB6/PB7 via AFIO mapping
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_AFIOEN
stm32.AFIO.MAPR |= stm32.AFIO_MAPR_USART1_REMAP
GPIO{PB6}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
GPIO{PB7}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_AFIOEN)
stm32.AFIO.MAPR.SetBits(stm32.AFIO_MAPR_USART1_REMAP)
PB6.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
PB7.Configure(PinConfig{Mode: PinInputModeFloating})
default:
// use standard TX/RX pins PA9 and PA10
GPIO{UART_TX_PIN}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
GPIO{UART_RX_PIN}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
UART_TX_PIN.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
UART_RX_PIN.Configure(PinConfig{Mode: PinInputModeFloating})
}
// Enable USART1 clock
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_USART1EN
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN)
// Set baud rate
uart.SetBaudRate(config.BaudRate)
// Enable USART1 port.
stm32.USART1.CR1 = stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE
stm32.USART1.CR1.Set(stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE)
// Enable RX IRQ.
arm.SetPriority(stm32.IRQ_USART1, 0xc0)
@@ -150,21 +150,21 @@ func (uart UART) Configure(config UARTConfig) {
func (uart UART) SetBaudRate(br uint32) {
// first divide by PCLK2 prescaler (div 1) and then desired baudrate
divider := CPU_FREQUENCY / br
stm32.USART1.BRR = stm32.RegValue(divider)
stm32.USART1.BRR.Set(divider)
}
// WriteByte writes a byte of data to the UART.
func (uart UART) WriteByte(c byte) error {
stm32.USART1.DR = stm32.RegValue(c)
stm32.USART1.DR.Set(uint32(c))
for (stm32.USART1.SR & stm32.USART_SR_TXE) == 0 {
for !stm32.USART1.SR.HasBits(stm32.USART_SR_TXE) {
}
return nil
}
//go:export USART1_IRQHandler
func handleUART1() {
UART1.Receive(byte((stm32.USART1.DR & 0xFF)))
UART1.Receive(byte((stm32.USART1.DR.Get() & 0xFF)))
}
// SPI on the STM32.
@@ -183,9 +183,9 @@ var (
// SPIConfig is used to store config info for SPI.
type SPIConfig struct {
Frequency uint32
SCK uint8
MOSI uint8
MISO uint8
SCK Pin
MOSI Pin
MISO Pin
LSBFirst bool
Mode uint8
}
@@ -198,9 +198,9 @@ type SPIConfig struct {
// - hardware SS pin?
func (spi SPI) Configure(config SPIConfig) {
// enable clock for SPI
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_SPI1EN
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN)
var conf uint16
var conf uint32
// set frequency
switch config.Frequency {
@@ -250,37 +250,37 @@ func (spi SPI) Configure(config SPIConfig) {
conf |= stm32.SPI_Mode_Master
// now set the configuration
spi.Bus.CR1 = stm32.RegValue(conf)
spi.Bus.CR1.Set(conf)
// init pins
spi.setPins(config.SCK, config.MOSI, config.MISO)
// enable SPI interface
spi.Bus.CR1 |= stm32.SPI_CR1_SPE
spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE)
}
// Transfer writes/reads a single byte using the SPI interface.
func (spi SPI) Transfer(w byte) (byte, error) {
// Write data to be transmitted to the SPI data register
spi.Bus.DR = stm32.RegValue(w)
spi.Bus.DR.Set(uint32(w))
// Wait until transmit complete
for (spi.Bus.SR & stm32.SPI_SR_TXE) == 0 {
for !spi.Bus.SR.HasBits(stm32.SPI_SR_TXE) {
}
// Wait until receive complete
for (spi.Bus.SR & stm32.SPI_SR_RXNE) == 0 {
for !spi.Bus.SR.HasBits(stm32.SPI_SR_RXNE) {
}
// Wait until SPI is not busy
for (spi.Bus.SR & stm32.SPI_SR_BSY) > 0 {
for spi.Bus.SR.HasBits(stm32.SPI_SR_BSY) {
}
// Return received data from SPI data register
return byte(spi.Bus.DR), nil
return byte(spi.Bus.DR.Get()), nil
}
func (spi SPI) setPins(sck, mosi, miso uint8) {
func (spi SPI) setPins(sck, mosi, miso Pin) {
if sck == 0 {
sck = SPI0_SCK_PIN
}
@@ -291,9 +291,9 @@ func (spi SPI) setPins(sck, mosi, miso uint8) {
miso = SPI0_MISO_PIN
}
GPIO{sck}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
GPIO{mosi}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_PUSH_PULL})
GPIO{miso}.Configure(GPIOConfig{Mode: GPIO_INPUT_MODE_FLOATING})
sck.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
mosi.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltPushPull})
miso.Configure(PinConfig{Mode: PinInputModeFloating})
}
// I2C on the STM32F103xx.
@@ -312,8 +312,8 @@ var (
// I2CConfig is used to store config info for I2C.
type I2CConfig struct {
Frequency uint32
SCL uint8
SDA uint8
SCL Pin
SDA Pin
}
// Configure is intended to setup the I2C interface.
@@ -324,26 +324,26 @@ func (i2c I2C) Configure(config I2CConfig) {
}
// enable clock for I2C
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_I2C1EN
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_I2C1EN)
// I2C1 pins
switch config.SDA {
case PB9:
config.SCL = PB8
// use alternate I2C1 pins PB8/PB9 via AFIO mapping
stm32.RCC.APB2ENR |= stm32.RCC_APB2ENR_AFIOEN
stm32.AFIO.MAPR |= stm32.AFIO_MAPR_I2C1_REMAP
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_AFIOEN)
stm32.AFIO.MAPR.SetBits(stm32.AFIO_MAPR_I2C1_REMAP)
default:
// use default I2C1 pins PB6/PB7
config.SDA = SDA_PIN
config.SCL = SCL_PIN
}
GPIO{config.SDA}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_OPEN_DRAIN})
GPIO{config.SCL}.Configure(GPIOConfig{Mode: GPIO_OUTPUT_50MHz + GPIO_OUTPUT_MODE_ALT_OPEN_DRAIN})
config.SDA.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltOpenDrain})
config.SCL.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltOpenDrain})
// Disable the selected I2C peripheral to configure
i2c.Bus.CR1 &^= stm32.I2C_CR1_PE
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE)
// pclk1 clock speed is main frequency divided by PCK1 prescaler (div 2)
pclk1 := uint32(CPU_FREQUENCY / 2)
@@ -351,40 +351,40 @@ func (i2c I2C) Configure(config I2CConfig) {
// set freqency range to pclk1 clock speed in Mhz.
// aka setting the value 36 means to use 36MhZ clock.
pclk1Mhz := pclk1 / 1000000
i2c.Bus.CR2 |= stm32.RegValue(pclk1Mhz)
i2c.Bus.CR2.SetBits(pclk1Mhz)
switch config.Frequency {
case TWI_FREQ_100KHZ:
// Normal mode speed calculation
ccr := pclk1 / (config.Frequency * 2)
i2c.Bus.CCR = stm32.RegValue(ccr)
i2c.Bus.CCR.Set(ccr)
// duty cycle 2
i2c.Bus.CCR &^= stm32.I2C_CCR_DUTY
i2c.Bus.CCR.ClearBits(stm32.I2C_CCR_DUTY)
// frequency standard mode
i2c.Bus.CCR &^= stm32.I2C_CCR_F_S
i2c.Bus.CCR.ClearBits(stm32.I2C_CCR_F_S)
// Set Maximum Rise Time for standard mode
i2c.Bus.TRISE = stm32.RegValue(pclk1Mhz)
i2c.Bus.TRISE.Set(pclk1Mhz)
case TWI_FREQ_400KHZ:
// Fast mode speed calculation
ccr := pclk1 / (config.Frequency * 3)
i2c.Bus.CCR = stm32.RegValue(ccr)
i2c.Bus.CCR.Set(ccr)
// duty cycle 2
i2c.Bus.CCR &^= stm32.I2C_CCR_DUTY
i2c.Bus.CCR.ClearBits(stm32.I2C_CCR_DUTY)
// frequency fast mode
i2c.Bus.CCR |= stm32.I2C_CCR_F_S
i2c.Bus.CCR.SetBits(stm32.I2C_CCR_F_S)
// Set Maximum Rise Time for fast mode
i2c.Bus.TRISE = stm32.RegValue(((pclk1Mhz * 300) / 1000))
i2c.Bus.TRISE.Set(((pclk1Mhz * 300) / 1000))
}
// re-enable the selected I2C peripheral
i2c.Bus.CR1 |= stm32.I2C_CR1_PE
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_PE)
}
// Tx does a single I2C transaction at the specified address.
@@ -435,11 +435,11 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// Disable ACK of received data
i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK)
// clear timeout here
timeout := i2cTimeout
for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 {
for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on read clear address")
@@ -447,10 +447,10 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// Generate stop condition
i2c.Bus.CR1 |= stm32.I2C_CR1_STOP
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP)
timeout = i2cTimeout
for (i2c.Bus.SR1 & stm32.I2C_SR1_RxNE) == 0 {
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_RxNE) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on read 1 byte")
@@ -458,17 +458,17 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// Read and return data byte from I2C data register
r[0] = byte(i2c.Bus.DR)
r[0] = byte(i2c.Bus.DR.Get())
// wait for stop
return i2c.waitForStop()
case 2:
// enable pos
i2c.Bus.CR1 |= stm32.I2C_CR1_POS
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_POS)
// Enable ACK of received data
i2c.Bus.CR1 |= stm32.I2C_CR1_ACK
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK)
// send address
err = i2c.sendAddress(uint8(addr), false)
@@ -478,7 +478,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
// clear address here
timeout := i2cTimeout
for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 {
for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on read clear address")
@@ -486,11 +486,11 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// Disable ACK of received data
i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK)
// wait for btf. we need a longer timeout here than normal.
timeout = 1000
for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 {
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on read 2 bytes")
@@ -498,18 +498,23 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// Generate stop condition
i2c.Bus.CR1 |= stm32.I2C_CR1_STOP
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP)
// read the 2 bytes by reading twice.
r[0] = byte(i2c.Bus.DR)
r[1] = byte(i2c.Bus.DR)
r[0] = byte(i2c.Bus.DR.Get())
r[1] = byte(i2c.Bus.DR.Get())
// wait for stop
return i2c.waitForStop()
err = i2c.waitForStop()
//disable pos
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_POS)
return err
case 3:
// Enable ACK of received data
i2c.Bus.CR1 |= stm32.I2C_CR1_ACK
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK)
// send address
err = i2c.sendAddress(uint8(addr), false)
@@ -519,7 +524,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
// clear address here
timeout := i2cTimeout
for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 {
for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on read clear address")
@@ -527,11 +532,11 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// Enable ACK of received data
i2c.Bus.CR1 |= stm32.I2C_CR1_ACK
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK)
// wait for btf. we need a longer timeout here than normal.
timeout = 1000
for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 {
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) {
timeout--
if timeout == 0 {
println("I2C timeout on read 3 bytes")
@@ -540,13 +545,13 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// Disable ACK of received data
i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK)
// read the first byte
r[0] = byte(i2c.Bus.DR)
r[0] = byte(i2c.Bus.DR.Get())
timeout = 1000
for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 {
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on read 3 bytes")
@@ -554,11 +559,11 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// Generate stop condition
i2c.Bus.CR1 |= stm32.I2C_CR1_STOP
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP)
// read the last 2 bytes by reading twice.
r[1] = byte(i2c.Bus.DR)
r[2] = byte(i2c.Bus.DR)
r[1] = byte(i2c.Bus.DR.Get())
r[2] = byte(i2c.Bus.DR.Get())
// wait for stop
return i2c.waitForStop()
@@ -574,7 +579,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
// clear address here
timeout := i2cTimeout
for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY) == 0 {
for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on read clear address")
@@ -583,11 +588,11 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
for i := 0; i < len(r)-3; i++ {
// Enable ACK of received data
i2c.Bus.CR1 |= stm32.I2C_CR1_ACK
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK)
// wait for btf. we need a longer timeout here than normal.
timeout = 1000
for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 {
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) {
timeout--
if timeout == 0 {
println("I2C timeout on read 3 bytes")
@@ -596,12 +601,12 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// read the next byte
r[i] = byte(i2c.Bus.DR)
r[i] = byte(i2c.Bus.DR.Get())
}
// wait for btf. we need a longer timeout here than normal.
timeout = 1000
for (i2c.Bus.SR1 & stm32.I2C_SR1_BTF) == 0 {
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_BTF) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on read more than 3 bytes")
@@ -609,19 +614,19 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// Disable ACK of received data
i2c.Bus.CR1 &^= stm32.I2C_CR1_ACK
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_ACK)
// get third from last byte
r[len(r)-3] = byte(i2c.Bus.DR)
r[len(r)-3] = byte(i2c.Bus.DR.Get())
// Generate stop condition
i2c.Bus.CR1 |= stm32.I2C_CR1_STOP
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP)
// get second from last byte
r[len(r)-2] = byte(i2c.Bus.DR)
r[len(r)-2] = byte(i2c.Bus.DR.Get())
timeout = i2cTimeout
for (i2c.Bus.SR1 & stm32.I2C_SR1_RxNE) == 0 {
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_RxNE) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on read last byte of more than 3")
@@ -629,7 +634,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// get last byte
r[len(r)-1] = byte(i2c.Bus.DR)
r[len(r)-1] = byte(i2c.Bus.DR.Get())
// wait for stop
return i2c.waitForStop()
@@ -645,7 +650,7 @@ const i2cTimeout = 500
func (i2c I2C) signalStart() error {
// Wait until I2C is not busy
timeout := i2cTimeout
for (i2c.Bus.SR2 & stm32.I2C_SR2_BUSY) > 0 {
for i2c.Bus.SR2.HasBits(stm32.I2C_SR2_BUSY) {
timeout--
if timeout == 0 {
return errors.New("I2C busy on start")
@@ -653,14 +658,14 @@ func (i2c I2C) signalStart() error {
}
// clear stop
i2c.Bus.CR1 &^= stm32.I2C_CR1_STOP
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_STOP)
// Generate start condition
i2c.Bus.CR1 |= stm32.I2C_CR1_START
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_START)
// Wait for I2C EV5 aka SB flag.
timeout = i2cTimeout
for (i2c.Bus.SR1 & stm32.I2C_SR1_SB) == 0 {
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_SB) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on start")
@@ -673,7 +678,7 @@ func (i2c I2C) signalStart() error {
// signalStop sends a stop signal and waits for it to succeed.
func (i2c I2C) signalStop() error {
// Generate stop condition
i2c.Bus.CR1 |= stm32.I2C_CR1_STOP
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_STOP)
// wait for stop
return i2c.waitForStop()
@@ -683,7 +688,7 @@ func (i2c I2C) signalStop() error {
func (i2c I2C) waitForStop() error {
// Wait until I2C is stopped
timeout := i2cTimeout
for (i2c.Bus.SR1 & stm32.I2C_SR1_STOPF) > 0 {
for i2c.Bus.SR1.HasBits(stm32.I2C_SR1_STOPF) {
timeout--
if timeout == 0 {
println("I2C timeout on wait for stop signal")
@@ -701,14 +706,14 @@ func (i2c I2C) sendAddress(address uint8, write bool) error {
data |= 1 // set read flag
}
i2c.Bus.DR = stm32.RegValue(data)
i2c.Bus.DR.Set(uint32(data))
// Wait for I2C EV6 event.
// Destination device acknowledges address
timeout := i2cTimeout
if write {
// EV6 which is ADDR flag.
for i2c.Bus.SR1&stm32.I2C_SR1_ADDR == 0 {
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_ADDR) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on send write address")
@@ -716,7 +721,7 @@ func (i2c I2C) sendAddress(address uint8, write bool) error {
}
timeout = i2cTimeout
for i2c.Bus.SR2&(stm32.I2C_SR2_MSL|stm32.I2C_SR2_BUSY|stm32.I2C_SR2_TRA) == 0 {
for !i2c.Bus.SR2.HasBits(stm32.I2C_SR2_MSL | stm32.I2C_SR2_BUSY | stm32.I2C_SR2_TRA) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on send write address")
@@ -724,7 +729,7 @@ func (i2c I2C) sendAddress(address uint8, write bool) error {
}
} else {
// I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED which is ADDR flag.
for (i2c.Bus.SR1 & stm32.I2C_SR1_ADDR) == 0 {
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_ADDR) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on send read address")
@@ -738,13 +743,13 @@ func (i2c I2C) sendAddress(address uint8, write bool) error {
// WriteByte writes a single byte to the I2C bus.
func (i2c I2C) WriteByte(data byte) error {
// Send data byte
i2c.Bus.DR = stm32.RegValue(data)
i2c.Bus.DR.Set(uint32(data))
// Wait for I2C EV8_2 when data has been physically shifted out and
// output on the bus.
// I2C_EVENT_MASTER_BYTE_TRANSMITTED is TXE flag.
timeout := i2cTimeout
for i2c.Bus.SR1&stm32.I2C_SR1_TxE == 0 {
for !i2c.Bus.SR1.HasBits(stm32.I2C_SR1_TxE) {
timeout--
if timeout == 0 {
return errors.New("I2C timeout on write")
+57 -57
View File
@@ -13,15 +13,15 @@ const CPU_FREQUENCY = 168000000
const (
// Mode Flag
GPIO_OUTPUT = 0
GPIO_INPUT = GPIO_INPUT_PULLDOWN
GPIO_INPUT_FLOATING = 1
GPIO_INPUT_PULLDOWN = 2
GPIO_INPUT_PULLUP = 3
PinOutput PinMode = 0
PinInput PinMode = PinInputFloating
PinInputFloating PinMode = 1
PinInputPulldown PinMode = 2
PinInputPullup PinMode = 3
// for UART
GPIO_UART_TX = 4
GPIO_UART_RX = 5
PinModeUartTX PinMode = 4
PinModeUartRX PinMode = 5
//GPIOx_MODER
GPIO_MODE_INPUT = 0
@@ -45,8 +45,8 @@ const (
GPIO_PULL_DOWN = 2
)
func (p GPIO) getPort() *stm32.GPIO_Type {
switch p.Pin / 16 {
func (p Pin) getPort() *stm32.GPIO_Type {
switch p / 16 {
case 0:
return stm32.GPIOA
case 1:
@@ -71,83 +71,83 @@ func (p GPIO) getPort() *stm32.GPIO_Type {
}
// enableClock enables the clock for this desired GPIO port.
func (p GPIO) enableClock() {
switch p.Pin / 16 {
func (p Pin) enableClock() {
switch p / 16 {
case 0:
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOAEN
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOAEN)
case 1:
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOBEN
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOBEN)
case 2:
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOCEN
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOCEN)
case 3:
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIODEN
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIODEN)
case 4:
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOEEN
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOEEN)
case 5:
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOFEN
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOFEN)
case 6:
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOGEN
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOGEN)
case 7:
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOHEN
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOHEN)
case 8:
stm32.RCC.AHB1ENR |= stm32.RCC_AHB1ENR_GPIOIEN
stm32.RCC.AHB1ENR.SetBits(stm32.RCC_AHB1ENR_GPIOIEN)
default:
panic("machine: unknown port")
}
}
// Configure this pin with the given configuration.
func (p GPIO) Configure(config GPIOConfig) {
func (p Pin) Configure(config PinConfig) {
// Configure the GPIO pin.
p.enableClock()
port := p.getPort()
pin := p.Pin % 16
pin := uint8(p) % 16
pos := pin * 2
if config.Mode == GPIO_INPUT_FLOATING {
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
port.PUPDR = stm32.RegValue((uint32(port.PUPDR)&^(0x3<<pos) | (uint32(GPIO_FLOATING) << pos)))
} else if config.Mode == GPIO_INPUT_PULLDOWN {
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
port.PUPDR = stm32.RegValue((uint32(port.PUPDR)&^(0x3<<pos) | (uint32(GPIO_PULL_DOWN) << pos)))
} else if config.Mode == GPIO_INPUT_PULLUP {
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
port.PUPDR = stm32.RegValue((uint32(port.PUPDR)&^(0x3<<pos) | (uint32(GPIO_PULL_UP) << pos)))
} else if config.Mode == GPIO_OUTPUT {
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_GENERAL_OUTPUT) << pos)))
port.OSPEEDR = stm32.RegValue((uint32(port.OSPEEDR)&^(0x3<<pos) | (uint32(GPIO_SPEED_HI) << pos)))
} else if config.Mode == GPIO_UART_TX {
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_ALTERNABTIVE) << pos)))
port.OSPEEDR = stm32.RegValue((uint32(port.OSPEEDR)&^(0x3<<pos) | (uint32(GPIO_SPEED_HI) << pos)))
port.PUPDR = stm32.RegValue((uint32(port.PUPDR)&^(0x3<<pos) | (uint32(GPIO_PULL_UP) << pos)))
if config.Mode == PinInputFloating {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_FLOATING) << pos)))
} else if config.Mode == PinInputPulldown {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_PULL_DOWN) << pos)))
} else if config.Mode == PinInputPullup {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_INPUT) << pos)))
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_PULL_UP) << pos)))
} else if config.Mode == PinOutput {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_GENERAL_OUTPUT) << pos)))
port.OSPEEDR.Set((uint32(port.OSPEEDR.Get())&^(0x3<<pos) | (uint32(GPIO_SPEED_HI) << pos)))
} else if config.Mode == PinModeUartTX {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_ALTERNABTIVE) << pos)))
port.OSPEEDR.Set((uint32(port.OSPEEDR.Get())&^(0x3<<pos) | (uint32(GPIO_SPEED_HI) << pos)))
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_PULL_UP) << pos)))
p.setAltFunc(0x7)
} else if config.Mode == GPIO_UART_RX {
port.MODER = stm32.RegValue((uint32(port.MODER)&^(0x3<<pos) | (uint32(GPIO_MODE_ALTERNABTIVE) << pos)))
port.PUPDR = stm32.RegValue((uint32(port.PUPDR)&^(0x3<<pos) | (uint32(GPIO_FLOATING) << pos)))
} else if config.Mode == PinModeUartRX {
port.MODER.Set((uint32(port.MODER.Get())&^(0x3<<pos) | (uint32(GPIO_MODE_ALTERNABTIVE) << pos)))
port.PUPDR.Set((uint32(port.PUPDR.Get())&^(0x3<<pos) | (uint32(GPIO_FLOATING) << pos)))
p.setAltFunc(0x7)
}
}
func (p GPIO) setAltFunc(af uint32) {
func (p Pin) setAltFunc(af uint32) {
port := p.getPort()
pin := p.Pin % 16
pin := uint8(p) % 16
pos := pin * 4
if pin >= 8 {
port.AFRH = stm32.RegValue(uint32(port.AFRH)&^(0xF<<pos) | ((af & 0xF) << pos))
port.AFRH.Set(uint32(port.AFRH.Get())&^(0xF<<pos) | ((af & 0xF) << pos))
} else {
port.AFRL = stm32.RegValue(uint32(port.AFRL)&^(0xF<<pos) | ((af & 0xF) << pos))
port.AFRL.Set(uint32(port.AFRL.Get())&^(0xF<<pos) | ((af & 0xF) << pos))
}
}
// Set the pin to high or low.
// Warning: only use this on an output pin!
func (p GPIO) Set(high bool) {
func (p Pin) Set(high bool) {
port := p.getPort()
pin := p.Pin % 16
pin := p % 16
if high {
port.BSRR = 1 << pin
port.BSRR.Set(1 << uint8(pin))
} else {
port.BSRR = 1 << (pin + 16)
port.BSRR.Set(1 << uint8(pin+16))
}
}
@@ -173,12 +173,12 @@ func (uart UART) Configure(config UARTConfig) {
switch config.TX {
default:
// use standard TX/RX pins PA2 and PA3
GPIO{UART_TX_PIN}.Configure(GPIOConfig{Mode: GPIO_UART_TX})
GPIO{UART_RX_PIN}.Configure(GPIOConfig{Mode: GPIO_UART_RX})
UART_TX_PIN.Configure(PinConfig{Mode: PinModeUartTX})
UART_RX_PIN.Configure(PinConfig{Mode: PinModeUartRX})
}
// Enable USART2 clock
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_USART2EN
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_USART2EN)
/*
Set baud rate(115200)
@@ -195,10 +195,10 @@ func (uart UART) Configure(config UARTConfig) {
| 115200 | 0x16D |
+----------+--------+
*/
stm32.USART2.BRR = 0x16c
stm32.USART2.BRR.Set(0x16c)
// Enable USART2 port.
stm32.USART2.CR1 = stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE
stm32.USART2.CR1.Set(stm32.USART_CR1_TE | stm32.USART_CR1_RE | stm32.USART_CR1_RXNEIE | stm32.USART_CR1_UE)
// Enable RX IRQ.
arm.SetPriority(stm32.IRQ_USART2, 0xc0)
@@ -207,14 +207,14 @@ func (uart UART) Configure(config UARTConfig) {
// WriteByte writes a byte of data to the UART.
func (uart UART) WriteByte(c byte) error {
stm32.USART2.DR = stm32.RegValue(c)
stm32.USART2.DR.Set(uint32(c))
for (stm32.USART2.SR & stm32.USART_SR_TXE) == 0 {
for !stm32.USART2.SR.HasBits(stm32.USART_SR_TXE) {
}
return nil
}
//go:export USART2_IRQHandler
func handleUSART2() {
UART1.Receive(byte((stm32.USART2.DR & 0xFF)))
UART1.Receive(byte((stm32.USART2.DR.Get() & 0xFF)))
}
+2 -2
View File
@@ -6,8 +6,8 @@ import "errors"
type UARTConfig struct {
BaudRate uint32
TX uint8
RX uint8
TX Pin
RX Pin
}
// To implement the UART interface for a board, you must declare a concrete type as follows:
+5 -5
View File
@@ -484,11 +484,11 @@ const (
// RoReg8 Reserved1[0x5];
// } UsbDeviceDescBank;
type usbDeviceDescBank struct {
ADDR sam.RegValue
PCKSIZE sam.RegValue
EXTREG sam.RegValue16
STATUS_BK sam.RegValue8
_reserved [5]sam.RegValue8
ADDR sam.Register32
PCKSIZE sam.Register32
EXTREG sam.Register16
STATUS_BK sam.Register8
_reserved [5]sam.Register8
}
type usbDeviceDescriptor struct {
-91
View File
@@ -1,91 +0,0 @@
// +build gc.conservative
package runtime
import (
"unsafe"
)
// Initialize the memory allocator.
// No memory may be allocated before this is called. That means the runtime and
// any packages the runtime depends upon may not allocate memory during package
// initialization.
func init() {
totalSize := heapEnd - heapStart
// Allocate some memory to keep 2 bits of information about every block.
metadataSize := totalSize / (blocksPerStateByte * bytesPerBlock)
// Align the pool.
poolStart = (heapStart + metadataSize + (bytesPerBlock - 1)) &^ (bytesPerBlock - 1)
poolEnd := heapEnd &^ (bytesPerBlock - 1)
numBlocks := (poolEnd - poolStart) / bytesPerBlock
endBlock = gcBlock(numBlocks)
if gcDebug {
println("heapStart: ", heapStart)
println("heapEnd: ", heapEnd)
println("total size: ", totalSize)
println("metadata size: ", metadataSize)
println("poolStart: ", poolStart)
println("# of blocks: ", numBlocks)
println("# of block states:", metadataSize*blocksPerStateByte)
}
if gcAsserts && metadataSize*blocksPerStateByte < numBlocks {
// sanity check
runtimePanic("gc: metadata array is too small")
}
// Set all block states to 'free'.
memzero(unsafe.Pointer(heapStart), metadataSize)
}
func alloc(size uintptr) unsafe.Pointer {
return heapAlloc(size)
}
// GC performs a garbage collection cycle.
func GC() {
if gcDebug {
println("running collection cycle...")
}
// Mark phase: mark all reachable objects, recursively.
markRoots(globalsStart, globalsEnd)
markRoots(getCurrentStackPointer(), stackTop) // assume a descending stack
// Sweep phase: free all non-marked objects and unmark marked objects for
// the next collection cycle.
sweep()
// Show how much has been sweeped, for debugging.
if gcDebug {
dumpHeap()
}
}
// markRoots reads all pointers from start to end (exclusive) and if they look
// like a heap pointer and are unmarked, marks them and scans that object as
// well (recursively). The start and end parameters must be valid pointers and
// must be aligned.
func markRoots(start, end uintptr) {
if gcDebug {
println("mark from", start, "to", end, int(end-start))
}
for addr := start; addr != end; addr += unsafe.Sizeof(addr) {
root := *(*uintptr)(unsafe.Pointer(addr))
if addressOnHeap(root) {
block := blockFromAddr(root)
head := block.findHead()
if head.state() != blockStateMark {
if gcDebug {
println("found unmarked pointer", root, "at address", addr)
}
head.setState(blockStateMark)
next := block.findNext()
// TODO: avoid recursion as much as possible
markRoots(head.address(), next.address())
}
}
}
}
@@ -1,4 +1,4 @@
// +build gc.leaking
// +build gc.dumb
package runtime
@@ -30,6 +30,18 @@ func alloc(size uintptr) unsafe.Pointer {
return unsafe.Pointer(addr)
}
func free(ptr unsafe.Pointer) {
// Memory is never freed.
}
func GC() {
// No-op.
}
func KeepAlive(x interface{}) {
// Unimplemented. Only required with SetFinalizer().
}
func SetFinalizer(obj interface{}, finalizer interface{}) {
// Unimplemented.
}
@@ -1,3 +1,5 @@
// +build gc.marksweep
package runtime
// This memory manager is a textbook mark/sweep implementation, heavily inspired
@@ -166,9 +168,42 @@ func (b gcBlock) unmark() {
}
}
// Initialize the memory allocator.
// No memory may be allocated before this is called. That means the runtime and
// any packages the runtime depends upon may not allocate memory during package
// initialization.
func init() {
totalSize := heapEnd - heapStart
// Allocate some memory to keep 2 bits of information about every block.
metadataSize := totalSize / (blocksPerStateByte * bytesPerBlock)
// Align the pool.
poolStart = (heapStart + metadataSize + (bytesPerBlock - 1)) &^ (bytesPerBlock - 1)
poolEnd := heapEnd &^ (bytesPerBlock - 1)
numBlocks := (poolEnd - poolStart) / bytesPerBlock
endBlock = gcBlock(numBlocks)
if gcDebug {
println("heapStart: ", heapStart)
println("heapEnd: ", heapEnd)
println("total size: ", totalSize)
println("metadata size: ", metadataSize)
println("poolStart: ", poolStart)
println("# of blocks: ", numBlocks)
println("# of block states:", metadataSize*blocksPerStateByte)
}
if gcAsserts && metadataSize*blocksPerStateByte < numBlocks {
// sanity check
runtimePanic("gc: metadata array is too small")
}
// Set all block states to 'free'.
memzero(unsafe.Pointer(heapStart), metadataSize)
}
// alloc tries to find some free space on the heap, possibly doing a garbage
// collection cycle if needed. If no space is free, it panics.
func heapAlloc(size uintptr) unsafe.Pointer {
func alloc(size uintptr) unsafe.Pointer {
if size == 0 {
return unsafe.Pointer(&zeroSizedAlloc)
}
@@ -240,6 +275,53 @@ func free(ptr unsafe.Pointer) {
// TODO: free blocks on request, when the compiler knows they're unused.
}
// GC performs a garbage collection cycle.
func GC() {
if gcDebug {
println("running collection cycle...")
}
// Mark phase: mark all reachable objects, recursively.
markRoots(globalsStart, globalsEnd)
markRoots(getCurrentStackPointer(), stackTop) // assume a descending stack
// Sweep phase: free all non-marked objects and unmark marked objects for
// the next collection cycle.
sweep()
// Show how much has been sweeped, for debugging.
if gcDebug {
dumpHeap()
}
}
// markRoots reads all pointers from start to end (exclusive) and if they look
// like a heap pointer and are unmarked, marks them and scans that object as
// well (recursively). The start and end parameters must be valid pointers and
// must be aligned.
func markRoots(start, end uintptr) {
if gcDebug {
println("mark from", start, "to", end, int(end-start))
}
for addr := start; addr != end; addr += unsafe.Sizeof(addr) {
root := *(*uintptr)(unsafe.Pointer(addr))
if looksLikePointer(root) {
block := blockFromAddr(root)
head := block.findHead()
if head.state() != blockStateMark {
if gcDebug {
println("found unmarked pointer", root, "at address", addr)
}
head.setState(blockStateMark)
next := block.findNext()
// TODO: avoid recursion as much as possible
markRoots(head.address(), next.address())
}
}
}
}
// Sweep goes through all memory and frees unmarked memory.
func sweep() {
freeCurrentObject := false
@@ -265,8 +347,10 @@ func sweep() {
}
}
// addressOnHeap returns whether this address points into the heap.
func addressOnHeap(ptr uintptr) bool {
// looksLikePointer returns whether this could be a pointer. Currently, it
// simply returns whether it lies anywhere in the heap. Go allows interior
// pointers so we can't check alignment or anything like that.
func looksLikePointer(ptr uintptr) bool {
return ptr >= poolStart && ptr < heapEnd
}
+12
View File
@@ -12,6 +12,18 @@ import (
func alloc(size uintptr) unsafe.Pointer
func free(ptr unsafe.Pointer) {
// Nothing to free when nothing gets allocated.
}
func GC() {
// Unimplemented.
}
func KeepAlive(x interface{}) {
// Unimplemented. Only required with SetFinalizer().
}
func SetFinalizer(obj interface{}, finalizer interface{}) {
// Unimplemented.
}
-116
View File
@@ -1,116 +0,0 @@
// +build gc.precise
package runtime
import (
"unsafe"
)
//go:extern runtime.trackedGlobalsStart
var trackedGlobalsStart uintptr
//go:extern runtime.trackedGlobalsLength
var trackedGlobalsLength uintptr
//go:extern runtime.trackedGlobalsBitmap
var trackedGlobalsBitmap [0]uint8
// Initialize the memory allocator.
// No memory may be allocated before this is called. That means the runtime and
// any packages the runtime depends upon may not allocate memory during package
// initialization.
func init() {
totalSize := heapEnd - heapStart
// Allocate some memory to keep 2 bits of information about every block.
metadataSize := totalSize / (blocksPerStateByte * bytesPerBlock)
// Align the pool.
poolStart = (heapStart + metadataSize + (bytesPerBlock - 1)) &^ (bytesPerBlock - 1)
poolEnd := heapEnd &^ (bytesPerBlock - 1)
numBlocks := (poolEnd - poolStart) / bytesPerBlock
endBlock = gcBlock(numBlocks)
if gcDebug {
println("heapStart: ", heapStart)
println("heapEnd: ", heapEnd)
println("total size: ", totalSize)
println("metadata size: ", metadataSize)
println("poolStart: ", poolStart)
println("# of blocks: ", numBlocks)
println("# of block states:", metadataSize*blocksPerStateByte)
}
if gcAsserts && metadataSize*blocksPerStateByte < numBlocks {
// sanity check
runtimePanic("gc: metadata array is too small")
}
// Set all block states to 'free'.
memzero(unsafe.Pointer(heapStart), metadataSize)
}
func alloc(size uintptr) unsafe.Pointer {
GC()
return heapAlloc(size)
}
// GC performs a garbage collection cycle.
func GC() {
if gcDebug {
println("\nrunning collection cycle...")
}
// Mark phase: mark all reachable objects, recursively.
markGlobals()
markRoots(getCurrentStackPointer(), stackTop) // assume a descending stack
// Sweep phase: free all non-marked objects and unmark marked objects for
// the next collection cycle.
sweep()
// Show how much has been sweeped, for debugging.
if gcDebug {
dumpHeap()
}
}
//go:nobounds
func markGlobals() {
for i := uintptr(0); i < trackedGlobalsLength; i++ {
if trackedGlobalsBitmap[i/8]&(1<<(i%8)) != 0 {
addr := trackedGlobalsStart + i*unsafe.Alignof(uintptr(0))
root := *(*uintptr)(unsafe.Pointer(addr))
markRoot(addr, root)
}
}
}
// markRoots reads all pointers from start to end (exclusive) and if they look
// like a heap pointer and are unmarked, marks them and scans that object as
// well (recursively). The start and end parameters must be valid pointers and
// must be aligned.
func markRoots(start, end uintptr) {
if gcDebug {
println("mark from", start, "to", end, int(end-start))
}
for addr := start; addr != end; addr += unsafe.Sizeof(addr) {
root := *(*uintptr)(unsafe.Pointer(addr))
markRoot(addr, root)
}
}
func markRoot(addr, root uintptr) {
if addressOnHeap(root) {
block := blockFromAddr(root)
head := block.findHead()
if head.state() != blockStateMark {
if gcDebug {
println("found unmarked pointer", root, "at address", addr)
}
head.setState(blockStateMark)
next := block.findNext()
// TODO: avoid recursion as much as possible
markRoots(head.address(), next.address())
}
}
}
+7 -3
View File
@@ -36,16 +36,20 @@ func isnil(ptr *uint8) bool {
}
// Panic when trying to dereference a nil pointer.
func nilpanic() {
func nilPanic() {
runtimePanic("nil pointer dereference")
}
// Panic when trying to acces an array or slice out of bounds.
func lookuppanic() {
func lookupPanic() {
runtimePanic("index out of range")
}
// Panic when trying to slice a slice out of bounds.
func slicepanic() {
func slicePanic() {
runtimePanic("slice out of range")
}
func blockingPanic() {
runtimePanic("trying to do blocking operation in exported function")
}
+1 -1
View File
@@ -10,7 +10,7 @@ const Compiler = "tinygo"
// package.
func initAll()
// A function call to this function is replaced withone of the following,
// A function call to this function is replaced with one of the following,
// depending on whether the scheduler is necessary:
//
// Without scheduler:
+54 -107
View File
@@ -36,12 +36,12 @@ func putchar(c byte) {
func initClocks() {
// Set 1 Flash Wait State for 48MHz, required for 3.3V operation according to SAMD21 Datasheet
sam.NVMCTRL.CTRLB |= (sam.NVMCTRL_CTRLB_RWS_HALF << sam.NVMCTRL_CTRLB_RWS_Pos)
sam.NVMCTRL.CTRLB.SetBits(sam.NVMCTRL_CTRLB_RWS_HALF << sam.NVMCTRL_CTRLB_RWS_Pos)
// Turn on the digital interface clock
sam.PM.APBAMASK |= sam.PM_APBAMASK_GCLK_
sam.PM.APBAMASK.SetBits(sam.PM_APBAMASK_GCLK_)
// turn off RTC
sam.PM.APBAMASK &^= sam.PM_APBAMASK_RTC_
sam.PM.APBAMASK.ClearBits(sam.PM_APBAMASK_RTC_)
// Enable OSC32K clock (Internal 32.768Hz oscillator).
// This requires registers that are not included in the SVD file.
@@ -61,42 +61,42 @@ func initClocks() {
// SYSCTRL_OSC32K_CALIB(calib) |
// SYSCTRL_OSC32K_STARTUP(0x6u) |
// SYSCTRL_OSC32K_EN32K | SYSCTRL_OSC32K_ENABLE;
sam.SYSCTRL.OSC32K = sam.RegValue((calib << sam.SYSCTRL_OSC32K_CALIB_Pos) |
sam.SYSCTRL.OSC32K.Set((calib << sam.SYSCTRL_OSC32K_CALIB_Pos) |
(0x6 << sam.SYSCTRL_OSC32K_STARTUP_Pos) |
sam.SYSCTRL_OSC32K_EN32K |
sam.SYSCTRL_OSC32K_EN1K |
sam.SYSCTRL_OSC32K_ENABLE)
// Wait for oscillator stabilization
for (sam.SYSCTRL.PCLKSR & sam.SYSCTRL_PCLKSR_OSC32KRDY) == 0 {
for !sam.SYSCTRL.PCLKSR.HasBits(sam.SYSCTRL_PCLKSR_OSC32KRDY) {
}
// Software reset the module to ensure it is re-initialized correctly
sam.GCLK.CTRL = sam.GCLK_CTRL_SWRST
sam.GCLK.CTRL.Set(sam.GCLK_CTRL_SWRST)
// Wait for reset to complete
for (sam.GCLK.CTRL&sam.GCLK_CTRL_SWRST) > 0 && (sam.GCLK.STATUS&sam.GCLK_STATUS_SYNCBUSY) > 0 {
for sam.GCLK.CTRL.HasBits(sam.GCLK_CTRL_SWRST) && sam.GCLK.STATUS.HasBits(sam.GCLK_STATUS_SYNCBUSY) {
}
// Put OSC32K as source of Generic Clock Generator 1
sam.GCLK.GENDIV = sam.RegValue((1 << sam.GCLK_GENDIV_ID_Pos) |
sam.GCLK.GENDIV.Set((1 << sam.GCLK_GENDIV_ID_Pos) |
(0 << sam.GCLK_GENDIV_DIV_Pos))
waitForSync()
// GCLK_GENCTRL_ID(1) | GCLK_GENCTRL_SRC_OSC32K | GCLK_GENCTRL_GENEN;
sam.GCLK.GENCTRL = sam.RegValue((1 << sam.GCLK_GENCTRL_ID_Pos) |
sam.GCLK.GENCTRL.Set((1 << sam.GCLK_GENCTRL_ID_Pos) |
(sam.GCLK_GENCTRL_SRC_OSC32K << sam.GCLK_GENCTRL_SRC_Pos) |
sam.GCLK_GENCTRL_GENEN)
waitForSync()
// Use Generic Clock Generator 1 as source for Generic Clock Multiplexer 0 (DFLL48M reference)
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_DFLL48 << sam.GCLK_CLKCTRL_ID_Pos) |
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_DFLL48 << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK1 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Remove the OnDemand mode, Bug http://avr32.icgroup.norway.atmel.com/bugzilla/show_bug.cgi?id=9905
sam.SYSCTRL.DFLLCTRL = sam.SYSCTRL_DFLLCTRL_ENABLE
sam.SYSCTRL.DFLLCTRL.Set(sam.SYSCTRL_DFLLCTRL_ENABLE)
// Wait for ready
for (sam.SYSCTRL.PCLKSR & sam.SYSCTRL_PCLKSR_DFLLRDY) == 0 {
for !sam.SYSCTRL.PCLKSR.HasBits(sam.SYSCTRL_PCLKSR_DFLLRDY) {
}
// Handle DFLL calibration based on info learned from Arduino SAMD implementation,
@@ -110,107 +110,107 @@ func initClocks() {
coarse = 0x1f
}
sam.SYSCTRL.DFLLVAL |= sam.RegValue(coarse << sam.SYSCTRL_DFLLVAL_COARSE_Pos)
sam.SYSCTRL.DFLLVAL |= (0x1ff << sam.SYSCTRL_DFLLVAL_FINE_Pos)
sam.SYSCTRL.DFLLVAL.SetBits(coarse << sam.SYSCTRL_DFLLVAL_COARSE_Pos)
sam.SYSCTRL.DFLLVAL.SetBits(0x1ff << sam.SYSCTRL_DFLLVAL_FINE_Pos)
// Write full configuration to DFLL control register
// SYSCTRL_DFLLMUL_CSTEP( 0x1f / 4 ) | // Coarse step is 31, half of the max value
// SYSCTRL_DFLLMUL_FSTEP( 10 ) |
// SYSCTRL_DFLLMUL_MUL( (48000) ) ;
sam.SYSCTRL.DFLLMUL = sam.RegValue(((31 / 4) << sam.SYSCTRL_DFLLMUL_CSTEP_Pos) |
sam.SYSCTRL.DFLLMUL.Set(((31 / 4) << sam.SYSCTRL_DFLLMUL_CSTEP_Pos) |
(10 << sam.SYSCTRL_DFLLMUL_FSTEP_Pos) |
(48000 << sam.SYSCTRL_DFLLMUL_MUL_Pos))
// disable DFLL
sam.SYSCTRL.DFLLCTRL = 0
sam.SYSCTRL.DFLLCTRL.Set(0)
waitForSync()
sam.SYSCTRL.DFLLCTRL |= sam.SYSCTRL_DFLLCTRL_MODE |
sam.SYSCTRL.DFLLCTRL.SetBits(sam.SYSCTRL_DFLLCTRL_MODE |
sam.SYSCTRL_DFLLCTRL_CCDIS |
sam.SYSCTRL_DFLLCTRL_USBCRM |
sam.SYSCTRL_DFLLCTRL_BPLCKC
sam.SYSCTRL_DFLLCTRL_BPLCKC)
// Wait for ready
for (sam.SYSCTRL.PCLKSR & sam.SYSCTRL_PCLKSR_DFLLRDY) == 0 {
for !sam.SYSCTRL.PCLKSR.HasBits(sam.SYSCTRL_PCLKSR_DFLLRDY) {
}
// Re-enable the DFLL
sam.SYSCTRL.DFLLCTRL |= sam.SYSCTRL_DFLLCTRL_ENABLE
sam.SYSCTRL.DFLLCTRL.SetBits(sam.SYSCTRL_DFLLCTRL_ENABLE)
// Wait for ready
for (sam.SYSCTRL.PCLKSR & sam.SYSCTRL_PCLKSR_DFLLRDY) == 0 {
for !sam.SYSCTRL.PCLKSR.HasBits(sam.SYSCTRL_PCLKSR_DFLLRDY) {
}
// Switch Generic Clock Generator 0 to DFLL48M. CPU will run at 48MHz.
sam.GCLK.GENDIV = sam.RegValue((0 << sam.GCLK_GENDIV_ID_Pos) |
sam.GCLK.GENDIV.Set((0 << sam.GCLK_GENDIV_ID_Pos) |
(0 << sam.GCLK_GENDIV_DIV_Pos))
waitForSync()
sam.GCLK.GENCTRL = sam.RegValue((0 << sam.GCLK_GENCTRL_ID_Pos) |
sam.GCLK.GENCTRL.Set((0 << sam.GCLK_GENCTRL_ID_Pos) |
(sam.GCLK_GENCTRL_SRC_DFLL48M << sam.GCLK_GENCTRL_SRC_Pos) |
sam.GCLK_GENCTRL_IDC |
sam.GCLK_GENCTRL_GENEN)
waitForSync()
// Modify PRESCaler value of OSC8M to have 8MHz
sam.SYSCTRL.OSC8M |= (sam.SYSCTRL_OSC8M_PRESC_0 << sam.SYSCTRL_OSC8M_PRESC_Pos)
sam.SYSCTRL.OSC8M &^= (1 << sam.SYSCTRL_OSC8M_ONDEMAND_Pos)
sam.SYSCTRL.OSC8M.SetBits(sam.SYSCTRL_OSC8M_PRESC_0 << sam.SYSCTRL_OSC8M_PRESC_Pos)
sam.SYSCTRL.OSC8M.ClearBits(1 << sam.SYSCTRL_OSC8M_ONDEMAND_Pos)
// Wait for oscillator stabilization
for (sam.SYSCTRL.PCLKSR & sam.SYSCTRL_PCLKSR_OSC8MRDY) == 0 {
for !sam.SYSCTRL.PCLKSR.HasBits(sam.SYSCTRL_PCLKSR_OSC8MRDY) {
}
// Use OSC8M as source for Generic Clock Generator 3
sam.GCLK.GENDIV = sam.RegValue((3 << sam.GCLK_GENDIV_ID_Pos))
sam.GCLK.GENDIV.Set((3 << sam.GCLK_GENDIV_ID_Pos))
waitForSync()
sam.GCLK.GENCTRL = sam.RegValue((3 << sam.GCLK_GENCTRL_ID_Pos) |
sam.GCLK.GENCTRL.Set((3 << sam.GCLK_GENCTRL_ID_Pos) |
(sam.GCLK_GENCTRL_SRC_OSC8M << sam.GCLK_GENCTRL_SRC_Pos) |
sam.GCLK_GENCTRL_GENEN)
waitForSync()
// Use OSC32K as source for Generic Clock Generator 2
// OSC32K/1 -> GCLK2 at 32KHz
sam.GCLK.GENDIV = sam.RegValue(2 << sam.GCLK_GENDIV_ID_Pos)
sam.GCLK.GENDIV.Set(2 << sam.GCLK_GENDIV_ID_Pos)
waitForSync()
sam.GCLK.GENCTRL = sam.RegValue((2 << sam.GCLK_GENCTRL_ID_Pos) |
sam.GCLK.GENCTRL.Set((2 << sam.GCLK_GENCTRL_ID_Pos) |
(sam.GCLK_GENCTRL_SRC_OSC32K << sam.GCLK_GENCTRL_SRC_Pos) |
sam.GCLK_GENCTRL_GENEN)
waitForSync()
// Use GCLK2 for RTC
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_RTC << sam.GCLK_CLKCTRL_ID_Pos) |
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_RTC << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK2 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Set the CPU, APBA, B, and C dividers
sam.PM.CPUSEL = sam.PM_CPUSEL_CPUDIV_DIV1
sam.PM.APBASEL = sam.PM_APBASEL_APBADIV_DIV1
sam.PM.APBBSEL = sam.PM_APBBSEL_APBBDIV_DIV1
sam.PM.APBCSEL = sam.PM_APBCSEL_APBCDIV_DIV1
sam.PM.CPUSEL.Set(sam.PM_CPUSEL_CPUDIV_DIV1)
sam.PM.APBASEL.Set(sam.PM_APBASEL_APBADIV_DIV1)
sam.PM.APBBSEL.Set(sam.PM_APBBSEL_APBBDIV_DIV1)
sam.PM.APBCSEL.Set(sam.PM_APBCSEL_APBCDIV_DIV1)
// Disable automatic NVM write operations
sam.NVMCTRL.CTRLB |= sam.NVMCTRL_CTRLB_MANW
sam.NVMCTRL.CTRLB.SetBits(sam.NVMCTRL_CTRLB_MANW)
}
func initRTC() {
// turn on digital interface clock
sam.PM.APBAMASK |= sam.PM_APBAMASK_RTC_
sam.PM.APBAMASK.SetBits(sam.PM_APBAMASK_RTC_)
// disable RTC
sam.RTC_MODE0.CTRL = 0
sam.RTC_MODE0.CTRL.Set(0)
waitForSync()
// reset RTC
sam.RTC_MODE0.CTRL |= sam.RTC_MODE0_CTRL_SWRST
sam.RTC_MODE0.CTRL.SetBits(sam.RTC_MODE0_CTRL_SWRST)
waitForSync()
// set Mode0 to 32-bit counter (mode 0) with prescaler 1 and GCLK2 is 32KHz/1
sam.RTC_MODE0.CTRL = sam.RegValue16((sam.RTC_MODE0_CTRL_MODE_COUNT32 << sam.RTC_MODE0_CTRL_MODE_Pos) |
sam.RTC_MODE0.CTRL.Set((sam.RTC_MODE0_CTRL_MODE_COUNT32 << sam.RTC_MODE0_CTRL_MODE_Pos) |
(sam.RTC_MODE0_CTRL_PRESCALER_DIV1 << sam.RTC_MODE0_CTRL_PRESCALER_Pos))
waitForSync()
// re-enable RTC
sam.RTC_MODE0.CTRL |= sam.RTC_MODE0_CTRL_ENABLE
sam.RTC_MODE0.CTRL.SetBits(sam.RTC_MODE0_CTRL_ENABLE)
waitForSync()
arm.SetPriority(sam.IRQ_RTC, 0xc0)
@@ -218,7 +218,7 @@ func initRTC() {
}
func waitForSync() {
for (sam.GCLK.STATUS & sam.GCLK_STATUS_SYNCBUSY) > 0 {
for sam.GCLK.STATUS.HasBits(sam.GCLK_STATUS_SYNCBUSY) {
}
}
@@ -250,11 +250,11 @@ func sleepTicks(d timeUnit) {
// ticks returns number of microseconds since start.
func ticks() timeUnit {
// request read of count
sam.RTC_MODE0.READREQ = sam.RTC_MODE0_READREQ_RREQ
sam.RTC_MODE0.READREQ.Set(sam.RTC_MODE0_READREQ_RREQ)
waitForSync()
rtcCounter := (uint64(sam.RTC_MODE0.COUNT) * 305) / 10 // each counter tick == 30.5us
offset := (rtcCounter - timerLastCounter) // change since last measurement
rtcCounter := (uint64(sam.RTC_MODE0.COUNT.Get()) * 305) / 10 // each counter tick == 30.5us
offset := (rtcCounter - timerLastCounter) // change since last measurement
timerLastCounter = rtcCounter
timestamp += timeUnit(offset) // TODO: not precise
return timestamp
@@ -269,16 +269,16 @@ func timerSleep(ticks uint32) {
}
// request read of count
sam.RTC_MODE0.READREQ = sam.RTC_MODE0_READREQ_RREQ
sam.RTC_MODE0.READREQ.Set(sam.RTC_MODE0_READREQ_RREQ)
waitForSync()
// set compare value
cnt := sam.RTC_MODE0.COUNT
sam.RTC_MODE0.COMP0 = sam.RegValue(uint32(cnt) + (ticks * 10 / 305)) // each counter tick == 30.5us
cnt := sam.RTC_MODE0.COUNT.Get()
sam.RTC_MODE0.COMP0.Set(uint32(cnt) + (ticks * 10 / 305)) // each counter tick == 30.5us
waitForSync()
// enable IRQ for CMP0 compare
sam.RTC_MODE0.INTENSET |= sam.RTC_MODE0_INTENSET_CMP0
sam.RTC_MODE0.INTENSET.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
for !timerWakeup {
arm.Asm("wfi")
@@ -288,70 +288,17 @@ func timerSleep(ticks uint32) {
//go:export RTC_IRQHandler
func handleRTC() {
// disable IRQ for CMP0 compare
sam.RTC_MODE0.INTFLAG = sam.RTC_MODE0_INTENSET_CMP0
sam.RTC_MODE0.INTFLAG.Set(sam.RTC_MODE0_INTENSET_CMP0)
timerWakeup = true
}
func initSERCOMClocks() {
// Turn on clock to SERCOM0 for UART0
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM0_
// Use GCLK0 for SERCOM0 aka UART0
// GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
// GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
// GCLK_CLKCTRL_CLKEN ;
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM0_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM1
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM1_
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM1_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM2
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM2_
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM2_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM3
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM3_
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM3_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM4
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM4_
// Use GCLK0 for SERCOM4
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM4_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM5
sam.PM.APBCMASK |= sam.PM_APBCMASK_SERCOM5_
// Use GCLK0 for SERCOM5
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_SERCOM5_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
}
func initUSBClock() {
// Turn on clock for USB
sam.PM.APBBMASK |= sam.PM_APBBMASK_USB_
sam.PM.APBBMASK.SetBits(sam.PM_APBBMASK_USB_)
// Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference)
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_USB << sam.GCLK_CLKCTRL_ID_Pos) |
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_USB << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
@@ -359,10 +306,10 @@ func initUSBClock() {
func initADCClock() {
// Turn on clock for ADC
sam.PM.APBCMASK |= sam.PM_APBCMASK_ADC_
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_ADC_)
// Put Generic Clock Generator 0 as source for Generic Clock Multiplexer for ADC.
sam.GCLK.CLKCTRL = sam.RegValue16((sam.GCLK_CLKCTRL_ID_ADC << sam.GCLK_CLKCTRL_ID_Pos) |
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_ADC << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
+42
View File
@@ -0,0 +1,42 @@
// +build sam,atsamd21,atsamd21e18
package runtime
import (
"device/sam"
)
func initSERCOMClocks() {
// Turn on clock to SERCOM0 for UART0
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM0_)
// Use GCLK0 for SERCOM0 aka UART0
// GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
// GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
// GCLK_CLKCTRL_CLKEN ;
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM0_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM1
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM1_)
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM1_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM2
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM2_)
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM2_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM3
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM3_)
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM3_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
}
+60
View File
@@ -0,0 +1,60 @@
// +build sam,atsamd21,atsamd21g18
package runtime
import (
"device/sam"
)
func initSERCOMClocks() {
// Turn on clock to SERCOM0 for UART0
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM0_)
// Use GCLK0 for SERCOM0 aka UART0
// GCLK_CLKCTRL_ID( clockId ) | // Generic Clock 0 (SERCOMx)
// GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
// GCLK_CLKCTRL_CLKEN ;
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM0_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM1
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM1_)
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM1_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM2
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM2_)
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM2_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM3
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM3_)
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM3_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM4
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM4_)
// Use GCLK0 for SERCOM4
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM4_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
// Turn on clock to SERCOM5
sam.PM.APBCMASK.SetBits(sam.PM_APBCMASK_SERCOM5_)
// Use GCLK0 for SERCOM5
sam.GCLK.CLKCTRL.Set((sam.GCLK_CLKCTRL_ID_SERCOM5_CORE << sam.GCLK_CLKCTRL_ID_Pos) |
(sam.GCLK_CLKCTRL_GEN_GCLK0 << sam.GCLK_CLKCTRL_GEN_Pos) |
sam.GCLK_CLKCTRL_CLKEN)
waitForSync()
}
+50
View File
@@ -41,11 +41,61 @@ func preinit() {
}
func abort() {
// disable all interrupts
arm.DisableInterrupts()
// lock up forever
for {
arm.Asm("wfi")
}
}
// The stack layout at the moment an interrupt occurs.
// Registers can be accessed if the stack pointer is cast to a pointer to this
// struct.
type interruptStack struct {
R0 uintptr
R1 uintptr
R2 uintptr
R3 uintptr
R12 uintptr
LR uintptr
PC uintptr
PSR uintptr
}
// This function is called at HardFault.
// Before this function is called, the stack pointer is reset to the initial
// stack pointer (loaded from addres 0x0) and the previous stack pointer is
// passed as an argument to this function. This allows for easy inspection of
// the stack the moment a HardFault occurs, but it means that the stack will be
// corrupted by this function and thus this handler must not attempt to recover.
//
// For details, see:
// https://community.arm.com/developer/ip-products/system/f/embedded-forum/3257/debugging-a-cortex-m0-hard-fault
// https://blog.feabhas.com/2013/02/developing-a-generic-hard-fault-handler-for-arm-cortex-m3cortex-m4/
//go:export handleHardFault
func handleHardFault(sp *interruptStack) {
print("fatal error: ")
if uintptr(unsafe.Pointer(sp)) < 0x20000000 {
print("stack overflow")
} else {
// TODO: try to find the cause of the hard fault. Especially on
// Cortex-M3 and higher it is possible to find more detailed information
// in special status registers.
print("HardFault")
}
print(" with sp=", sp)
if uintptr(unsafe.Pointer(&sp.PC)) >= 0x20000000 {
// Only print the PC if it points into memory.
// It may not point into memory during a stack overflow, so check that
// first before accessing the stack.
print(" pc=", sp.PC)
}
println()
abort()
}
// Implement memset for LLVM and compiler-rt.
//go:export memset
func libc_memset(ptr unsafe.Pointer, c byte, size uintptr) {
+10 -10
View File
@@ -32,16 +32,16 @@ func init() {
func initLFCLK() {
if machine.HasLowFrequencyCrystal {
nrf.CLOCK.LFCLKSRC = nrf.CLOCK_LFCLKSTAT_SRC_Xtal
nrf.CLOCK.LFCLKSRC.Set(nrf.CLOCK_LFCLKSTAT_SRC_Xtal)
}
nrf.CLOCK.TASKS_LFCLKSTART = 1
for nrf.CLOCK.EVENTS_LFCLKSTARTED == 0 {
nrf.CLOCK.TASKS_LFCLKSTART.Set(1)
for nrf.CLOCK.EVENTS_LFCLKSTARTED.Get() == 0 {
}
nrf.CLOCK.EVENTS_LFCLKSTARTED = 0
nrf.CLOCK.EVENTS_LFCLKSTARTED.Set(0)
}
func initRTC() {
nrf.RTC1.TASKS_START = 1
nrf.RTC1.TASKS_START.Set(1)
arm.SetPriority(nrf.IRQ_RTC1, 0xc0) // low priority
arm.EnableIRQ(nrf.IRQ_RTC1)
}
@@ -72,7 +72,7 @@ var (
// overflow the counter, leading to incorrect results. This might be fixed by
// handling the overflow event.
func ticks() timeUnit {
rtcCounter := uint32(nrf.RTC1.COUNTER)
rtcCounter := uint32(nrf.RTC1.COUNTER.Get())
offset := (rtcCounter - rtcLastCounter) & 0xffffff // change since last measurement
rtcLastCounter = rtcCounter
timestamp += timeUnit(offset) // TODO: not precise
@@ -85,7 +85,7 @@ type isrFlag bool
var rtc_wakeup isrFlag
func rtc_sleep(ticks uint32) {
nrf.RTC1.INTENSET = nrf.RTC_INTENSET_COMPARE0
nrf.RTC1.INTENSET.Set(nrf.RTC_INTENSET_COMPARE0)
rtc_wakeup = false
if ticks == 1 {
// Race condition (even in hardware) at ticks == 1.
@@ -93,7 +93,7 @@ func rtc_sleep(ticks uint32) {
// describes.
ticks = 2
}
nrf.RTC1.CC[0] = (nrf.RTC1.COUNTER + nrf.RegValue(ticks)) & 0x00ffffff
nrf.RTC1.CC[0].Set((nrf.RTC1.COUNTER.Get() + ticks) & 0x00ffffff)
for !rtc_wakeup {
arm.Asm("wfi")
}
@@ -101,7 +101,7 @@ func rtc_sleep(ticks uint32) {
//go:export RTC1_IRQHandler
func handleRTC1() {
nrf.RTC1.INTENCLR = nrf.RTC_INTENSET_COMPARE0
nrf.RTC1.EVENTS_COMPARE[0] = 0
nrf.RTC1.INTENCLR.Set(nrf.RTC_INTENSET_COMPARE0)
nrf.RTC1.EVENTS_COMPARE[0].Set(0)
rtc_wakeup = true
}
+35 -35
View File
@@ -21,33 +21,33 @@ func putchar(c byte) {
// initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz).
func initCLK() {
stm32.FLASH.ACR |= stm32.FLASH_ACR_LATENCY_2 // Two wait states, per datasheet
stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE1_DIV_2 // prescale PCLK1 = HCLK/2
stm32.RCC.CFGR |= stm32.RCC_CFGR_PPRE2_DIV_NONE // prescale PCLK2 = HCLK/1
stm32.RCC.CR |= stm32.RCC_CR_HSEON // enable HSE clock
stm32.FLASH.ACR.SetBits(stm32.FLASH_ACR_LATENCY_2) // Two wait states, per datasheet
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PPRE1_DIV_2) // prescale PCLK1 = HCLK/2
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PPRE2_DIV_NONE) // prescale PCLK2 = HCLK/1
stm32.RCC.CR.SetBits(stm32.RCC_CR_HSEON) // enable HSE clock
// wait for the HSEREADY flag
for (stm32.RCC.CR & stm32.RCC_CR_HSERDY) == 0 {
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSERDY) {
}
stm32.RCC.CR |= stm32.RCC_CR_HSION // enable HSI clock
stm32.RCC.CR.SetBits(stm32.RCC_CR_HSION) // enable HSI clock
// wait for the HSIREADY flag
for (stm32.RCC.CR & stm32.RCC_CR_HSIRDY) == 0 {
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSIRDY) {
}
stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLSRC // set PLL source to HSE
stm32.RCC.CFGR |= stm32.RCC_CFGR_PLLMUL_9 // multiply by 9
stm32.RCC.CR |= stm32.RCC_CR_PLLON // enable the PLL
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PLLSRC) // set PLL source to HSE
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_PLLMUL_9) // multiply by 9
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON) // enable the PLL
// wait for the PLLRDY flag
for (stm32.RCC.CR & stm32.RCC_CR_PLLRDY) == 0 {
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
}
stm32.RCC.CFGR |= stm32.RCC_CFGR_SW_PLL // set clock source to pll
stm32.RCC.CFGR.SetBits(stm32.RCC_CFGR_SW_PLL) // set clock source to pll
// wait for PLL to be CLK
for (stm32.RCC.CFGR & stm32.RCC_CFGR_SWS_PLL) == 0 {
for !stm32.RCC.CFGR.HasBits(stm32.RCC_CFGR_SWS_PLL) {
}
}
@@ -65,43 +65,43 @@ var timerWakeup isrFlag
func initRTC() {
// Enable the PWR and BKP.
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_PWREN | stm32.RCC_APB1ENR_BKPEN
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN | stm32.RCC_APB1ENR_BKPEN)
// access to backup register
stm32.PWR.CR |= stm32.PWR_CR_DBP
stm32.PWR.CR.SetBits(stm32.PWR_CR_DBP)
// Enable LSE
stm32.RCC.BDCR |= stm32.RCC_BDCR_LSEON
stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_LSEON)
// wait until LSE is ready
for stm32.RCC.BDCR&stm32.RCC_BDCR_LSERDY == 0 {
for !stm32.RCC.BDCR.HasBits(stm32.RCC_BDCR_LSERDY) {
}
// Select LSE
stm32.RCC.BDCR |= stm32.RCC_RTCCLKSource_LSE
stm32.RCC.BDCR.SetBits(stm32.RCC_RTCCLKSource_LSE)
// set prescaler to "max" per datasheet
stm32.RTC.PRLH = stm32.RTC_PRLH_PRLH_Msk
stm32.RTC.PRLL = stm32.RTC_PRLL_PRLL_Msk
stm32.RTC.PRLH.Set(stm32.RTC_PRLH_PRLH_Msk)
stm32.RTC.PRLL.Set(stm32.RTC_PRLL_PRLL_Msk)
// set count to zero
stm32.RTC.CNTH = 0x0
stm32.RTC.CNTL = 0x0
stm32.RTC.CNTH.Set(0x0)
stm32.RTC.CNTL.Set(0x0)
// Enable RTC
stm32.RCC.BDCR |= stm32.RCC_BDCR_RTCEN
stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_RTCEN)
// Clear RSF
stm32.RTC.CRL &^= stm32.RTC_CRL_RSF
stm32.RTC.CRL.ClearBits(stm32.RTC_CRL_RSF)
// Wait till flag is set
for stm32.RTC.CRL&stm32.RTC_CRL_RSF == 0 {
for !stm32.RTC.CRL.HasBits(stm32.RTC_CRL_RSF) {
}
}
// Enable the TIM3 clock.
func initTIM() {
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_TIM3EN
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
arm.SetPriority(stm32.IRQ_TIM3, 0xc3)
arm.EnableIRQ(stm32.IRQ_TIM3)
@@ -122,10 +122,10 @@ func sleepTicks(d timeUnit) {
// number of ticks (microseconds) since start.
func ticks() timeUnit {
// convert RTC counter from seconds to microseconds
timerCounter := uint64(stm32.RTC.CNTH<<16|stm32.RTC.CNTL) * 1000 * 1000
timerCounter := uint64(stm32.RTC.CNTH.Get()<<16|stm32.RTC.CNTL.Get()) * 1000 * 1000
// add the fractional part of current time using DIV register
timerCounter += uint64(0x8000-stm32.RTC.DIVL) * 31
timerCounter += uint64(0x8000-stm32.RTC.DIVL.Get()) * 31
// change since last measurement
offset := (timerCounter - timerLastCounter)
@@ -165,16 +165,16 @@ func timerSleep(ticks uint32) {
// The current scaling only supports a range of 100 usec to 6553 msec.
// prescale counter down from 72mhz to 10khz aka 0.1 ms frequency.
stm32.TIM3.PSC = machine.CPU_FREQUENCY/10000 - 1 // 7199
stm32.TIM3.PSC.Set(machine.CPU_FREQUENCY/10000 - 1) // 7199
// set duty aka duration
stm32.TIM3.ARR = stm32.RegValue(ticks/100) - 1 // convert from microseconds to 0.1 ms
stm32.TIM3.ARR.Set(ticks/100 - 1) // convert from microseconds to 0.1 ms
// Enable the hardware interrupt.
stm32.TIM3.DIER |= stm32.TIM_DIER_UIE
stm32.TIM3.DIER.SetBits(stm32.TIM_DIER_UIE)
// Enable the timer.
stm32.TIM3.CR1 |= stm32.TIM_CR1_CEN
stm32.TIM3.CR1.SetBits(stm32.TIM_CR1_CEN)
// wait till timer wakes up
for !timerWakeup {
@@ -184,12 +184,12 @@ func timerSleep(ticks uint32) {
//go:export TIM3_IRQHandler
func handleTIM3() {
if (stm32.TIM3.SR & stm32.TIM_SR_UIF) > 0 {
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
// Disable the timer.
stm32.TIM3.CR1 &^= stm32.TIM_CR1_CEN
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN)
// clear the update flag
stm32.TIM3.SR &^= stm32.TIM_SR_UIF
stm32.TIM3.SR.ClearBits(stm32.TIM_SR_UIF)
// timer was triggered
timerWakeup = true
+40 -39
View File
@@ -42,58 +42,59 @@ func initCLK() {
// Reset clock registers
// Set HSION
stm32.RCC.CR |= stm32.RCC_CR_HSION
for (stm32.RCC.CR & stm32.RCC_CR_HSIRDY) == 0 {
stm32.RCC.CR.SetBits(stm32.RCC_CR_HSION)
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_HSIRDY) {
}
// Reset CFGR
stm32.RCC.CFGR = 0x00000000
stm32.RCC.CFGR.Set(0x00000000)
// Reset HSEON, CSSON and PLLON
stm32.RCC.CR &= 0xFEF6FFFF
stm32.RCC.CR.ClearBits(stm32.RCC_CR_HSEON | stm32.RCC_CR_CSSON | stm32.RCC_CR_PLLON)
// Reset PLLCFGR
stm32.RCC.PLLCFGR = 0x24003010
stm32.RCC.PLLCFGR.Set(0x24003010)
// Reset HSEBYP
stm32.RCC.CR &= 0xFFFBFFFF
stm32.RCC.CR.ClearBits(stm32.RCC_CR_HSEBYP)
// Disable all interrupts
stm32.RCC.CIR = 0x00000000
stm32.RCC.CIR.Set(0x00000000)
// Set up the clock
var startupCounter uint32 = 0
// Enable HSE
stm32.RCC.CR = stm32.RCC_CR_HSEON
stm32.RCC.CR.Set(stm32.RCC_CR_HSEON)
// Wait till HSE is ready and if timeout is reached exit
for {
startupCounter++
if (stm32.RCC.CR&stm32.RCC_CR_HSERDY != 0) || (startupCounter == HSE_STARTUP_TIMEOUT) {
if stm32.RCC.CR.HasBits(stm32.RCC_CR_HSERDY) || (startupCounter == HSE_STARTUP_TIMEOUT) {
break
}
}
if (stm32.RCC.CR & stm32.RCC_CR_HSERDY) != 0 {
if stm32.RCC.CR.HasBits(stm32.RCC_CR_HSERDY) {
// Enable high performance mode, System frequency up to 168MHz
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_PWREN
stm32.PWR.CR |= 0x4000 // PWR_CR_VOS
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
stm32.PWR.CR.SetBits(0x4000) // PWR_CR_VOS
// HCLK = SYSCLK / 1
stm32.RCC.CFGR |= (0x0 << stm32.RCC_CFGR_HPRE_Pos)
stm32.RCC.CFGR.SetBits(0x0 << stm32.RCC_CFGR_HPRE_Pos)
// PCLK2 = HCLK / 2
stm32.RCC.CFGR |= (0x4 << stm32.RCC_CFGR_PPRE2_Pos)
stm32.RCC.CFGR.SetBits(0x4 << stm32.RCC_CFGR_PPRE2_Pos)
// PCLK1 = HCLK / 4
stm32.RCC.CFGR |= (0x5 << stm32.RCC_CFGR_PPRE1_Pos)
stm32.RCC.CFGR.SetBits(0x5 << stm32.RCC_CFGR_PPRE1_Pos)
// Configure the main PLL
// PLL Options - See RM0090 Reference Manual pg. 95
stm32.RCC.PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) - 1) << 16) |
(1 << stm32.RCC_PLLCFGR_PLLSRC_Pos) | (PLL_Q << 24)
stm32.RCC.PLLCFGR.Set(PLL_M | (PLL_N << 6) | (((PLL_P >> 1) - 1) << 16) |
(1 << stm32.RCC_PLLCFGR_PLLSRC_Pos) | (PLL_Q << 24))
// Enable main PLL
stm32.RCC.CR |= stm32.RCC_CR_PLLON
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON)
// Wait till the main PLL is ready
for (stm32.RCC.CR & stm32.RCC_CR_PLLRDY) == 0 {
for (stm32.RCC.CR.Get() & stm32.RCC_CR_PLLRDY) == 0 {
}
// Configure Flash prefetch, Instruction cache, Data cache and wait state
stm32.FLASH.ACR = stm32.FLASH_ACR_ICEN | stm32.FLASH_ACR_DCEN | (5 << stm32.FLASH_ACR_LATENCY_Pos)
stm32.FLASH.ACR.Set(stm32.FLASH_ACR_ICEN | stm32.FLASH_ACR_DCEN | (5 << stm32.FLASH_ACR_LATENCY_Pos))
// Select the main PLL as system clock source
stm32.RCC.CFGR &^= stm32.RCC_CFGR_SW0 | stm32.RCC_CFGR_SW1
stm32.RCC.CFGR |= (0x2 << stm32.RCC_CFGR_SW0_Pos)
for (stm32.RCC.CFGR & (0x3 << stm32.RCC_CFGR_SWS0_Pos)) != (0x2 << stm32.RCC_CFGR_SWS0_Pos) {
stm32.RCC.CFGR.ClearBits(stm32.RCC_CFGR_SW0 | stm32.RCC_CFGR_SW1)
stm32.RCC.CFGR.SetBits(0x2 << stm32.RCC_CFGR_SW0_Pos)
for (stm32.RCC.CFGR.Get() & (0x3 << stm32.RCC_CFGR_SWS0_Pos)) != (0x2 << stm32.RCC_CFGR_SWS0_Pos) {
}
} else {
@@ -102,7 +103,7 @@ func initCLK() {
}
}
// Enable the CCM RAM clock
stm32.RCC.AHB1ENR |= (1 << 20)
stm32.RCC.AHB1ENR.SetBits(1 << 20)
}
@@ -120,7 +121,7 @@ var timerWakeup isrFlag
// Enable the TIM3 clock.(sleep count)
func initTIM3() {
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_TIM3EN
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM3EN)
arm.SetPriority(stm32.IRQ_TIM3, 0xc3)
arm.EnableIRQ(stm32.IRQ_TIM3)
@@ -128,17 +129,17 @@ func initTIM3() {
// Enable the TIM7 clock.(tick count)
func initTIM7() {
stm32.RCC.APB1ENR |= stm32.RCC_APB1ENR_TIM7EN
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_TIM7EN)
// CK_INT = APB1 x2 = 84mhz
stm32.TIM7.PSC = 84000000/10000 - 1 // 84mhz to 10khz(0.1ms)
stm32.TIM7.ARR = stm32.RegValue(10) - 1 // interrupt per 1ms
stm32.TIM7.PSC.Set(84000000/10000 - 1) // 84mhz to 10khz(0.1ms)
stm32.TIM7.ARR.Set(10 - 1) // interrupt per 1ms
// Enable the hardware interrupt.
stm32.TIM7.DIER |= stm32.TIM_DIER_UIE
stm32.TIM7.DIER.SetBits(stm32.TIM_DIER_UIE)
// Enable the timer.
stm32.TIM7.CR1 |= stm32.TIM_CR1_CEN
stm32.TIM7.CR1.SetBits(stm32.TIM_CR1_CEN)
arm.SetPriority(stm32.IRQ_TIM7, 0xc1)
arm.EnableIRQ(stm32.IRQ_TIM7)
@@ -163,20 +164,20 @@ func timerSleep(ticks uint32) {
// CK_INT = APB1 x2 = 84mhz
// prescale counter down from 84mhz to 10khz aka 0.1 ms frequency.
stm32.TIM3.PSC = 84000000/10000 - 1 // 8399
stm32.TIM3.PSC.Set(84000000/10000 - 1) // 8399
// set duty aka duration
arr := (ticks / 100) - 1 // convert from microseconds to 0.1 ms
if arr == 0 {
arr = 1 // avoid blocking
}
stm32.TIM3.ARR = stm32.RegValue(arr)
stm32.TIM3.ARR.Set(arr)
// Enable the hardware interrupt.
stm32.TIM3.DIER |= stm32.TIM_DIER_UIE
stm32.TIM3.DIER.SetBits(stm32.TIM_DIER_UIE)
// Enable the timer.
stm32.TIM3.CR1 |= stm32.TIM_CR1_CEN
stm32.TIM3.CR1.SetBits(stm32.TIM_CR1_CEN)
// wait till timer wakes up
for !timerWakeup {
@@ -186,12 +187,12 @@ func timerSleep(ticks uint32) {
//go:export TIM3_IRQHandler
func handleTIM3() {
if (stm32.TIM3.SR & stm32.TIM_SR_UIF) > 0 {
if stm32.TIM3.SR.HasBits(stm32.TIM_SR_UIF) {
// Disable the timer.
stm32.TIM3.CR1 &^= stm32.TIM_CR1_CEN
stm32.TIM3.CR1.ClearBits(stm32.TIM_CR1_CEN)
// clear the update flag
stm32.TIM3.SR &^= stm32.TIM_SR_UIF
stm32.TIM3.SR.ClearBits(stm32.TIM_SR_UIF)
// timer was triggered
timerWakeup = true
@@ -200,9 +201,9 @@ func handleTIM3() {
//go:export TIM7_IRQHandler
func handleTIM7() {
if (stm32.TIM7.SR & stm32.TIM_SR_UIF) > 0 {
if stm32.TIM7.SR.HasBits(stm32.TIM_SR_UIF) {
// clear the update flag
stm32.TIM7.SR &^= stm32.TIM_SR_UIF
stm32.TIM7.SR.ClearBits(stm32.TIM_SR_UIF)
tickCount++
}
}
+8
View File
@@ -18,6 +18,9 @@ func malloc(size uintptr) unsafe.Pointer
//go:export abort
func abort()
//go:export exit
func exit(code int)
//go:export clock_gettime
func clock_gettime(clk_id uint, ts *timespec)
@@ -75,3 +78,8 @@ func monotime() uint64 {
func ticks() timeUnit {
return timeUnit(monotime())
}
//go:linkname syscall_Exit syscall.Exit
func syscall_Exit(code int) {
exit(code)
}
+8 -1
View File
@@ -37,9 +37,16 @@ func putchar(c byte) {
resource_write(stdout, &c, 1)
}
var handleEvent func()
//go:linkname setEventHandler syscall/js.setEventHandler
func setEventHandler(fn func()) {
// TODO
handleEvent = fn
}
//go:export resume
func resume() {
handleEvent()
}
//go:export go_scheduler
+3
View File
@@ -120,6 +120,9 @@ func setTaskPromisePtr(task *coroutine, value unsafe.Pointer) {
// getTaskPromisePtr is a helper function to get the current .ptr field from a
// coroutine promise.
func getTaskPromisePtr(task *coroutine) unsafe.Pointer {
if task == nil {
blockingPanic()
}
return task.promise().ptr
}
+4 -3
View File
@@ -166,9 +166,10 @@ func decodeUTF8(s string, index uintptr) (rune, uintptr) {
}
}
// indexByte returns the index of the first instance of c in s, or -1 if c is not present in s.
//go:linkname indexByte strings.IndexByte
func indexByte(s string, c byte) int {
// indexByteString returns the index of the first instance of c in s, or -1 if c
// is not present in s.
//go:linkname indexByteString internal/bytealg.IndexByteString
func indexByteString(s string, c byte) int {
for i := 0; i < len(s); i++ {
if s[i] == c {
return i
+12
View File
@@ -0,0 +1,12 @@
// +build !go1.12
package runtime
// indexByte provides compatibility with Go 1.11.
// See the following:
// https://github.com/tinygo-org/tinygo/issues/351
// https://github.com/golang/go/commit/ad4a58e31501bce5de2aad90a620eaecdc1eecb8
//go:linkname indexByte strings.IndexByte
func indexByte(s string, c byte) int {
return indexByteString(s, c)
}
+27
View File
@@ -5,11 +5,13 @@ import (
"errors"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"os/user"
"path/filepath"
"runtime"
"strconv"
"strings"
)
@@ -22,6 +24,7 @@ type TargetSpec struct {
Inherits []string `json:"inherits"`
Triple string `json:"llvm-target"`
CPU string `json:"cpu"`
Features []string `json:"features"`
GOOS string `json:"goos"`
GOARCH string `json:"goarch"`
BuildTags []string `json:"build-tags"`
@@ -50,6 +53,7 @@ func (spec *TargetSpec) copyProperties(spec2 *TargetSpec) {
if spec2.CPU != "" {
spec.CPU = spec2.CPU
}
spec.Features = append(spec.Features, spec2.Features...)
if spec2.GOOS != "" {
spec.GOOS = spec2.GOOS
}
@@ -368,3 +372,26 @@ func isGoroot(goroot string) bool {
_, err := os.Stat(filepath.Join(goroot, "src", "runtime", "internal", "sys", "zversion.go"))
return err == nil
}
// getGorootVersion returns the major and minor version for a given GOROOT path.
// If the goroot cannot be determined, (0, 0) is returned.
func getGorootVersion(goroot string) (major, minor int) {
data, err := ioutil.ReadFile(filepath.Join(goroot, "VERSION"))
if err != nil {
return
}
s := string(data)
if s[:2] != "go" {
return
}
parts := strings.Split(s[2:], ".")
if len(parts) < 2 {
return
}
// Ignore the errors, strconv.Atoi will return 0 on most errors and we
// don't really handle errors here anyway.
major, _ = strconv.Atoi(parts[0])
minor, _ = strconv.Atoi(parts[1])
return
}
+15
View File
@@ -0,0 +1,15 @@
{
"inherits": ["cortex-m"],
"llvm-target": "armv6m-none-eabi",
"build-tags": ["atsamd21e18", "atsamd21", "sam"],
"cflags": [
"--target=armv6m-none-eabi",
"-Qunused-arguments"
],
"ldflags": [
"-T", "targets/atsamd21.ld"
],
"extra-files": [
"src/device/sam/atsamd21e18a.s"
]
}
+4 -1
View File
@@ -3,7 +3,7 @@
"goos": "linux",
"goarch": "arm",
"compiler": "clang",
"gc": "precise",
"gc": "marksweep",
"linker": "ld.lld",
"rtlib": "compiler-rt",
"cflags": [
@@ -19,5 +19,8 @@
"ldflags": [
"--gc-sections"
],
"extra-files": [
"src/device/arm/cortexm.s"
],
"gdb": "arm-none-eabi-gdb"
}
+5
View File
@@ -0,0 +1,5 @@
{
"inherits": ["atsamd21g18a"],
"build-tags": ["sam", "atsamd21g18a", "feather_m0"],
"flash": "bossac -d -i -e -w -v -R --offset=0x2000 {hex}"
}
+5
View File
@@ -0,0 +1,5 @@
{
"inherits": ["atsamd21e18a"],
"build-tags": ["sam", "atsamd21e18a", "trinket_m0"],
"flash": "bossac -d -i -e -w -v -R --offset=0x2000 {hex}"
}
+1
View File
@@ -13,6 +13,7 @@
],
"ldflags": [
"--allow-undefined",
"--no-threads",
"--export-all"
],
"emulator": ["node", "targets/wasm_exec.js"]
+21 -23
View File
@@ -240,9 +240,9 @@
},
// func valueIndex(v ref, i int) ref
//"syscall/js.valueIndex": (sp) => {
// storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
//},
"syscall/js.valueIndex": (ret_addr, v_addr, i) => {
storeValue(ret_addr, Reflect.get(loadValue(v_addr), i));
},
// valueSetIndex(v ref, i int, x ref)
//"syscall/js.valueSetIndex": (sp) => {
@@ -291,9 +291,9 @@
},
// func valueLength(v ref) int
//"syscall/js.valueLength": (sp) => {
// setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
//},
"syscall/js.valueLength": (v_addr) => {
return loadValue(v_addr).length;
},
// valuePrepareString(v ref) (ref, int)
"syscall/js.valuePrepareString": (ret_addr, v_addr) => {
@@ -352,25 +352,23 @@
}
}
static _makeCallbackHelper(id, pendingCallbacks, go) {
return function () {
pendingCallbacks.push({ id: id, args: arguments });
go._resolveCallbackPromise();
};
_resume() {
if (this.exited) {
throw new Error("Go program has already exited");
}
this._inst.exports.resume();
if (this.exited) {
this._resolveExitPromise();
}
}
static _makeEventCallbackHelper(preventDefault, stopPropagation, stopImmediatePropagation, fn) {
return function (event) {
if (preventDefault) {
event.preventDefault();
}
if (stopPropagation) {
event.stopPropagation();
}
if (stopImmediatePropagation) {
event.stopImmediatePropagation();
}
fn(event);
_makeFuncWrapper(id) {
const go = this;
return function () {
const event = { id: id, this: this, args: arguments };
go._pendingEvent = event;
go._resume();
return event.result;
};
}
}
+1
View File
@@ -17,6 +17,7 @@ int globalStructSize = sizeof(globalStruct);
short globalArray[3] = {5, 6, 7};
joined_t globalUnion;
int globalUnionSize = sizeof(globalUnion);
option_t globalOption = optionG;
int fortytwo() {
return 42;
+18
View File
@@ -75,6 +75,24 @@ func main() {
println("n in chain:", list.n)
list = (*C.list_t)(list.next)
}
// named enum
var _ C.enum_option = C.optionA
var _ C.option_t = C.optionA
println("option:", C.globalOption)
println("option A:", C.optionA)
println("option B:", C.optionB)
println("option C:", C.optionC)
println("option D:", C.optionD)
println("option E:", C.optionE)
println("option F:", C.optionF)
println("option G:", C.optionG)
// anonymous enum
var _ C.option2_t = C.option2A
var _ C.option3_t = C.option3A
println("option 2A:", C.option2A)
println("option 3A:", C.option3A)
}
func printUnion(union C.joined_t) C.joined_t {
+19
View File
@@ -47,6 +47,24 @@ void unionSetShort(short s);
void unionSetFloat(float f);
void unionSetData(short f0, short f1, short f2);
typedef enum option {
optionA,
optionB,
optionC = -5,
optionD,
optionE = 10,
optionF,
optionG,
} option_t;
typedef enum {
option2A = 20,
} option2_t;
typedef enum {
option3A = 21,
} option3_t;
// test globals and datatypes
extern int global;
extern int unusedGlobal;
@@ -66,6 +84,7 @@ extern int globalStructSize;
extern short globalArray[3];
extern joined_t globalUnion;
extern int globalUnionSize;
extern option_t globalOption;
// test duplicate definitions
int add(int a, int b);
+10
View File
@@ -35,3 +35,13 @@ struct: 3 5
n in chain: 3
n in chain: 6
n in chain: 7
option: 12
option A: 0
option B: 1
option C: -5
option D: -4
option E: 10
option F: 11
option G: 12
option 2A: 20
option 3A: 21
+6
View File
@@ -4,12 +4,18 @@ import (
"fmt"
"math/rand"
"os"
"strings"
)
func main() {
// package os, fmt
fmt.Println("stdin: ", os.Stdin.Fd())
fmt.Println("stdout:", os.Stdout.Fd())
fmt.Println("stderr:", os.Stderr.Fd())
// package math/rand
fmt.Println("pseudorandom number:", rand.Int31())
// package strings
fmt.Println("strings.IndexByte:", strings.IndexByte("asdf", 'd'))
}

Some files were not shown because too many files have changed in this diff Show More