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