Compare commits

..

1 Commits

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

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