Compare commits

..

1 Commits

Author SHA1 Message Date
sago35 fa79f561ac ci: changed to generate only files that exist in targets 2021-04-08 20:25:13 +09:00
162 changed files with 1189 additions and 6754 deletions
+12 -30
View File
@@ -68,17 +68,14 @@ commands:
steps:
- restore_cache:
keys:
- llvm-source-11-v2
- llvm-source-11-v1
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-11-v2
key: llvm-source-11-v1
paths:
- llvm-project/clang/lib/Headers
- llvm-project/clang/include
- llvm-project/lld/include
- llvm-project/llvm/include
- llvm-project
build-wasi-libc:
steps:
- restore_cache:
@@ -157,15 +154,12 @@ commands:
- llvm-source-linux
- restore_cache:
keys:
- llvm-build-11-linux-v3-assert
- llvm-build-11-linux-v2-assert
- run:
name: "Build LLVM"
command: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# install dependencies
sudo apt-get install cmake ninja-build
# hack ninja to use less jobs
@@ -173,10 +167,9 @@ commands:
chmod +x /go/bin/ninja
# build!
make ASSERT=1 llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
fi
- save_cache:
key: llvm-build-11-linux-v3-assert
key: llvm-build-11-linux-v2-assert
paths:
llvm-build
- run: make ASSERT=1
@@ -225,15 +218,12 @@ commands:
- llvm-source-linux
- restore_cache:
keys:
- llvm-build-11-linux-v3-noassert
- llvm-build-11-linux-v2-noassert
- run:
name: "Build LLVM"
command: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# install dependencies
sudo apt-get install cmake ninja-build
# hack ninja to use less jobs
@@ -241,10 +231,9 @@ commands:
chmod +x /go/bin/ninja
# build!
make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
fi
- save_cache:
key: llvm-build-11-linux-v3-noassert
key: llvm-build-11-linux-v2-noassert
paths:
llvm-build
- build-wasi-libc
@@ -298,36 +287,29 @@ commands:
- go-cache-macos-v2-{{ checksum "go.mod" }}
- restore_cache:
keys:
- llvm-source-11-macos-v2
- llvm-source-11-macos-v1
- run:
name: "Fetch LLVM source"
command: make llvm-source
- save_cache:
key: llvm-source-11-macos-v2
key: llvm-source-11-macos-v1
paths:
- llvm-project/clang/lib/Headers
- llvm-project/clang/include
- llvm-project/lld/include
- llvm-project/llvm/include
- llvm-project
- restore_cache:
keys:
- llvm-build-11-macos-v3
- llvm-build-11-macos-v2
- run:
name: "Build LLVM"
command: |
if [ ! -f llvm-build/lib/liblldELF.a ]
then
# fetch LLVM source
rm -rf llvm-project
make llvm-source
# install dependencies
HOMEBREW_NO_AUTO_UPDATE=1 brew install cmake ninja
# build!
make llvm-build
find llvm-build -name CMakeFiles -prune -exec rm -r '{}' \;
fi
- save_cache:
key: llvm-build-11-macos-v3
key: llvm-build-11-macos-v2
paths:
llvm-build
- restore_cache:
+11 -23
View File
@@ -120,22 +120,22 @@ gen-device-avr:
@GO111MODULE=off $(GO) fmt ./src/device/avr
build/gen-device-svd: ./tools/gen-device-svd/*.go
$(GO) build -o $@ ./tools/gen-device-svd/
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -o $@ ./tools/gen-device-svd/
gen-device-esp: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Espressif-Community -interrupts=software lib/cmsis-svd/data/Espressif-Community/ src/device/esp/
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Espressif-Community -only-used -interrupts=software lib/cmsis-svd/data/Espressif-Community/ src/device/esp/
GO111MODULE=off $(GO) fmt ./src/device/esp
gen-device-nrf: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/NordicSemiconductor/nrfx/tree/master/mdk lib/nrfx/mdk/ src/device/nrf/
./build/gen-device-svd -source=https://github.com/NordicSemiconductor/nrfx/tree/master/mdk -only-used lib/nrfx/mdk/ src/device/nrf/
GO111MODULE=off $(GO) fmt ./src/device/nrf
gen-device-nxp: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/NXP lib/cmsis-svd/data/NXP/ src/device/nxp/
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/NXP -only-used lib/cmsis-svd/data/NXP/ src/device/nxp/
GO111MODULE=off $(GO) fmt ./src/device/nxp
gen-device-sam: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Atmel lib/cmsis-svd/data/Atmel/ src/device/sam/
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Atmel -only-used lib/cmsis-svd/data/Atmel/ src/device/sam/
GO111MODULE=off $(GO) fmt ./src/device/sam
gen-device-sifive: build/gen-device-svd
@@ -143,18 +143,18 @@ gen-device-sifive: build/gen-device-svd
GO111MODULE=off $(GO) fmt ./src/device/sifive
gen-device-kendryte: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Kendryte-Community -interrupts=software lib/cmsis-svd/data/Kendryte-Community/ src/device/kendryte/
./build/gen-device-svd -source=https://github.com/posborne/cmsis-svd/tree/master/data/Kendryte-Community -only-used -interrupts=software lib/cmsis-svd/data/Kendryte-Community/ src/device/kendryte/
GO111MODULE=off $(GO) fmt ./src/device/kendryte
gen-device-stm32: build/gen-device-svd
./build/gen-device-svd -source=https://github.com/tinygo-org/stm32-svd lib/stm32-svd/svd src/device/stm32/
./build/gen-device-svd -source=https://github.com/tinygo-org/stm32-svd -only-used lib/stm32-svd/svd src/device/stm32/
GO111MODULE=off $(GO) fmt ./src/device/stm32
# Get LLVM sources.
$(LLVM_PROJECTDIR)/llvm:
$(LLVM_PROJECTDIR)/README.md:
git clone -b xtensa_release_11.0.0 --depth=1 https://github.com/tinygo-org/llvm-project $(LLVM_PROJECTDIR)
llvm-source: $(LLVM_PROJECTDIR)/llvm
llvm-source: $(LLVM_PROJECTDIR)/README.md
# Configure LLVM.
TINYGO_SOURCE_DIR=$(shell pwd)
@@ -226,6 +226,8 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit examples/microbit-blink
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit-v2 examples/microbit-blink
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/pininterrupt
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/serial
@@ -254,10 +256,6 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit-s110v8 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit-v2 examples/microbit-blink
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=microbit-v2-s113v7 examples/microbit-blink
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nrf52840-mdk examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10031 examples/blinky1
@@ -290,8 +288,6 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.gba -target=gameboy-advance examples/gba-display
@$(MD5SUM) test.gba
$(TINYGO) build -size short -o test.hex -target=grandcentral-m4 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m4 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m4 examples/blinky1
@@ -338,10 +334,6 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=p1am-100 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=atsame54-xpro examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m4-can examples/blinky1
@$(MD5SUM) test.hex
# test pwm
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/pwm
@$(MD5SUM) test.hex
@@ -382,10 +374,6 @@ ifneq ($(AVR), 0)
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino -scheduler=tasks examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-mega1280 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-mega1280 examples/pwm
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=arduino-nano examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=digispark examples/blinky1
+1 -3
View File
@@ -43,14 +43,13 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
The following 57 microcontroller boards are currently supported:
The following 55 microcontroller boards are currently supported:
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
* [Adafruit CLUE](https://www.adafruit.com/product/4500)
* [Adafruit Feather M0](https://www.adafruit.com/product/2772)
* [Adafruit Feather M4](https://www.adafruit.com/product/3857)
* [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759)
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
* [Adafruit ItsyBitsy M0](https://www.adafruit.com/product/3727)
@@ -78,7 +77,6 @@ The following 57 microcontroller boards are currently supported:
* [Game Boy Advance](https://en.wikipedia.org/wiki/Game_Boy_Advance)
* [Makerdiary nRF52840-MDK](https://wiki.makerdiary.com/nrf52840-mdk/)
* [Makerdiary nRF52840-MDK USB Dongle](https://wiki.makerdiary.com/nrf52840-mdk-usb-dongle/)
* [Microchip SAM E54 Xplained Pro](https://www.microchip.com/developmenttools/productdetails/atsame54-xpro)
* [nice!nano](https://docs.nicekeyboards.com/#/nice!nano/)
* [Nintendo Switch](https://www.nintendo.com/switch/)
* [Nordic Semiconductor PCA10031](https://www.nordicsemi.com/eng/Products/nRF51-Dongle)
+34 -162
View File
@@ -52,17 +52,14 @@ type BuildResult struct {
// key, avoiding the need for recompiling all dependencies when only the
// implementation of an imported package changes.
type packageAction struct {
ImportPath string
CompilerVersion int // compiler.Version
InterpVersion int // interp.Version
LLVMVersion string
Config *compiler.Config
CFlags []string
FileHashes map[string]string // hash of every file that's part of the package
Imports map[string]string // map from imported package to action ID hash
OptLevel int // LLVM optimization level (0-3)
SizeLevel int // LLVM optimization for size level (0-2)
UndefinedGlobals []string // globals that are left as external globals (no initializer)
ImportPath string
CompilerVersion int // compiler.Version
InterpVersion int // interp.Version
LLVMVersion string
Config *compiler.Config
CFlags []string
FileHashes map[string]string // hash of every file that's part of the package
Imports map[string]string // map from imported package to action ID hash
}
// Build performs a single package to executable Go build. It takes in a package
@@ -130,30 +127,20 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
var packageJobs []*compileJob
packageBitcodePaths := make(map[string]string)
packageActionIDs := make(map[string]string)
optLevel, sizeLevel, _ := config.OptLevels()
for _, pkg := range lprogram.Sorted() {
pkg := pkg // necessary to avoid a race condition
var undefinedGlobals []string
for name := range config.Options.GlobalValues[pkg.Pkg.Path()] {
undefinedGlobals = append(undefinedGlobals, name)
}
sort.Strings(undefinedGlobals)
// Create a cache key: a hash from the action ID below that contains all
// the parameters for the build.
actionID := packageAction{
ImportPath: pkg.ImportPath,
CompilerVersion: compiler.Version,
InterpVersion: interp.Version,
LLVMVersion: llvm.Version,
Config: compilerConfig,
CFlags: pkg.CFlags,
FileHashes: make(map[string]string, len(pkg.FileHashes)),
Imports: make(map[string]string, len(pkg.Pkg.Imports())),
OptLevel: optLevel,
SizeLevel: sizeLevel,
UndefinedGlobals: undefinedGlobals,
ImportPath: pkg.ImportPath,
CompilerVersion: compiler.Version,
InterpVersion: interp.Version,
LLVMVersion: llvm.Version,
Config: compilerConfig,
CFlags: pkg.CFlags,
FileHashes: make(map[string]string, len(pkg.FileHashes)),
Imports: make(map[string]string, len(pkg.Pkg.Imports())),
}
for filePath, hash := range pkg.FileHashes {
actionID.FileHashes[filePath] = hex.EncodeToString(hash)
@@ -204,25 +191,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
return errors.New("verification error after compiling package " + pkg.ImportPath)
}
// Erase all globals that are part of the undefinedGlobals list.
// This list comes from the -ldflags="-X pkg.foo=val" option.
// Instead of setting the value directly in the AST (which would
// mean the value, which may be a secret, is stored in the build
// cache), the global itself is left external (undefined) and is
// only set at the end of the compilation.
for _, name := range undefinedGlobals {
globalName := pkg.Pkg.Path() + "." + name
global := mod.NamedGlobal(globalName)
if global.IsNil() {
return errors.New("global not found: " + globalName)
}
name := global.Name()
newGlobal := llvm.AddGlobal(mod, global.Type().ElementType(), name+".tmp")
global.ReplaceAllUsesWith(newGlobal)
global.EraseFromParentAsGlobal()
newGlobal.SetName(name)
}
// Try to interpret package initializers at compile time.
// It may only be possible to do this partially, in which case
// it is completed after all IR files are linked.
@@ -238,38 +206,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
return errors.New("verification error after interpreting " + pkgInit.Name())
}
if sizeLevel >= 2 {
// Set the "optsize" attribute to make slightly smaller
// binaries at the cost of some performance.
kind := llvm.AttributeKindID("optsize")
attr := mod.Context().CreateEnumAttribute(kind, 0)
for fn := mod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
fn.AddFunctionAttr(attr)
}
}
// Run function passes for each function in the module.
// These passes are intended to be run on each function right
// after they're created to reduce IR size (and maybe also for
// cache locality to improve performance), but for now they're
// run here for each function in turn. Maybe this can be
// improved in the future.
builder := llvm.NewPassManagerBuilder()
defer builder.Dispose()
builder.SetOptLevel(optLevel)
builder.SetSizeLevel(sizeLevel)
funcPasses := llvm.NewFunctionPassManagerForModule(mod)
defer funcPasses.Dispose()
builder.PopulateFunc(funcPasses)
funcPasses.InitializeFunc()
for fn := mod.FirstFunction(); !fn.IsNil(); fn = llvm.NextFunction(fn) {
if fn.IsDeclaration() {
continue
}
funcPasses.RunFunc(fn)
}
funcPasses.FinalizeFunc()
// Serialize the LLVM module as a bitcode file.
// Write to a temporary path that is renamed to the destination
// file to avoid race conditions with other TinyGo invocatiosn
@@ -300,13 +236,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
if err != nil {
return err
}
// 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
return os.Rename(f.Name(), bitcodePath)
},
}
jobs = append(jobs, job)
@@ -500,7 +430,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
job := &compileJob{
description: "compile extra file " + path,
run: func(job *compileJob) error {
result, err := compileAndCacheCFile(abspath, dir, config.CFlags(), config.Options.PrintCommands)
result, err := compileAndCacheCFile(abspath, dir, config.CFlags(), config)
job.result = result
return err
},
@@ -519,7 +449,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
job := &compileJob{
description: "compile CGo file " + abspath,
run: func(job *compileJob) error {
result, err := compileAndCacheCFile(abspath, dir, pkg.CFlags, config.Options.PrintCommands)
result, err := compileAndCacheCFile(abspath, dir, pkg.CFlags, config)
job.result = result
return err
},
@@ -673,12 +603,6 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
transform.ApplyFunctionSections(mod) // -ffunction-sections
}
// Insert values from -ldflags="-X ..." into the IR.
err = setGlobalValues(mod, config.Options.GlobalValues)
if err != nil {
return err
}
// Browsers cannot handle external functions that have type i64 because it
// cannot be represented exactly in JavaScript (JS only has doubles). To
// keep functions interoperable, pass int64 types as pointers to
@@ -693,8 +617,21 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
// Optimization levels here are roughly the same as Clang, but probably not
// exactly.
optLevel, sizeLevel, inlinerThreshold := config.OptLevels()
errs := transform.Optimize(mod, config, optLevel, sizeLevel, inlinerThreshold)
var errs []error
switch config.Options.Opt {
case "none", "0":
errs = transform.Optimize(mod, config, 0, 0, 0) // -O0
case "1":
errs = transform.Optimize(mod, config, 1, 0, 0) // -O1
case "2":
errs = transform.Optimize(mod, config, 2, 0, 225) // -O2
case "s":
errs = transform.Optimize(mod, config, 2, 1, 225) // -Os
case "z":
errs = transform.Optimize(mod, config, 2, 2, 5) // -Oz, default
default:
return errors.New("unknown optimization level: -opt=" + config.Options.Opt)
}
if len(errs) > 0 {
return newMultiError(errs)
}
@@ -716,71 +653,6 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
return nil
}
// setGlobalValues sets the global values from the -ldflags="-X ..." compiler
// option in the given module. An error may be returned if the global is not of
// the expected type.
func setGlobalValues(mod llvm.Module, globals map[string]map[string]string) error {
var pkgPaths []string
for pkgPath := range globals {
pkgPaths = append(pkgPaths, pkgPath)
}
sort.Strings(pkgPaths)
for _, pkgPath := range pkgPaths {
pkg := globals[pkgPath]
var names []string
for name := range pkg {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
value := pkg[name]
globalName := pkgPath + "." + name
global := mod.NamedGlobal(globalName)
if global.IsNil() || !global.Initializer().IsNil() {
// The global either does not exist (optimized away?) or has
// some value, in which case it has already been initialized at
// package init time.
continue
}
// A strin is a {ptr, len} pair. We need these types to build the
// initializer.
initializerType := global.Type().ElementType()
if initializerType.TypeKind() != llvm.StructTypeKind || initializerType.StructName() == "" {
return fmt.Errorf("%s: not a string", globalName)
}
elementTypes := initializerType.StructElementTypes()
if len(elementTypes) != 2 {
return fmt.Errorf("%s: not a string", globalName)
}
// Create a buffer for the string contents.
bufInitializer := mod.Context().ConstString(value, false)
buf := llvm.AddGlobal(mod, bufInitializer.Type(), ".string")
buf.SetInitializer(bufInitializer)
buf.SetAlignment(1)
buf.SetUnnamedAddr(true)
buf.SetLinkage(llvm.PrivateLinkage)
// Create the string value, which is a {ptr, len} pair.
zero := llvm.ConstInt(mod.Context().Int32Type(), 0, false)
ptr := llvm.ConstGEP(buf, []llvm.Value{zero, zero})
if ptr.Type() != elementTypes[0] {
return fmt.Errorf("%s: not a string", globalName)
}
length := llvm.ConstInt(elementTypes[1], uint64(len(value)), false)
initializer := llvm.ConstNamedStruct(initializerType, []llvm.Value{
ptr,
length,
})
// Set the initializer. No initializer should be set at this point.
global.SetInitializer(initializer)
}
}
return nil
}
// functionStackSizes keeps stack size information about a single function
// (usually a goroutine).
type functionStackSize struct {
+8 -12
View File
@@ -17,6 +17,7 @@ import (
"strings"
"unicode"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/goenv"
"tinygo.org/x/go-llvm"
)
@@ -56,7 +57,7 @@ import (
// depfile but without invalidating its name. For this reason, the depfile is
// written on each new compilation (even when it seems unnecessary). However, it
// could in rare cases lead to a stale file fetched from the cache.
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands bool) (string, error) {
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, config *compileopts.Config) (string, error) {
// Hash input file.
fileHash, err := hashFile(abspath)
if err != nil {
@@ -67,12 +68,14 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
buf, err := json.Marshal(struct {
Path string
Hash string
Compiler string
Flags []string
LLVMVersion string
}{
Path: abspath,
Hash: fileHash,
Flags: cflags,
Compiler: config.Target.Compiler,
Flags: config.CFlags(),
LLVMVersion: llvm.Version,
})
if err != nil {
@@ -121,17 +124,10 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
flags := append([]string{}, cflags...) // copy cflags
flags = append(flags, "-MD", "-MV", "-MTdeps", "-MF", depTmpFile.Name()) // autogenerate dependencies
flags = append(flags, "-c", "-o", objTmpFile.Name(), abspath)
if strings.ToLower(filepath.Ext(abspath)) == ".s" {
// If this is an assembly file (.s or .S, lowercase or uppercase), then
// we'll need to add -Qunused-arguments because many parameters are
// relevant to C, not assembly. And with -Werror, having meaningless
// flags (for the assembler) is a compiler error.
flags = append(flags, "-Qunused-arguments")
if config.Options.PrintCommands {
fmt.Printf("%s %s\n", config.Target.Compiler, strings.Join(flags, " "))
}
if printCommands {
fmt.Printf("clang %s\n", strings.Join(flags, " "))
}
err = runCCompiler(flags...)
err = runCCompiler(config.Target.Compiler, flags...)
if err != nil {
return "", &commandError{"failed to build", abspath, err}
}
+1 -1
View File
@@ -136,7 +136,7 @@ func (l *Library) load(target, cpu, tmpdir string) (job *compileJob, err error)
var compileArgs []string
compileArgs = append(compileArgs, args...)
compileArgs = append(compileArgs, "-o", objpath, srcpath)
err := runCCompiler(compileArgs...)
err := runCCompiler("clang", compileArgs...)
if err != nil {
return &commandError{"failed to build", srcpath, err}
}
+13 -4
View File
@@ -9,8 +9,8 @@ import (
)
// runCCompiler invokes a C compiler with the given arguments.
func runCCompiler(flags ...string) error {
if hasBuiltinTools {
func runCCompiler(command string, flags ...string) error {
if hasBuiltinTools && command == "clang" {
// Compile this with the internal Clang compiler.
headerPath := getClangHeaderPath(goenv.Get("TINYGOROOT"))
if headerPath == "" {
@@ -23,8 +23,17 @@ func runCCompiler(flags ...string) error {
return cmd.Run()
}
// Compile this with an external invocation of the Clang compiler.
return execCommand(commands["clang"], flags...)
// Running some other compiler. Maybe it has been defined in the
// commands map (unlikely).
if cmdNames, ok := commands[command]; ok {
return execCommand(cmdNames, flags...)
}
// Alternatively, run the compiler directly.
cmd := exec.Command(command, flags...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
// link invokes a linker with the given name and flags.
+2 -23
View File
@@ -118,27 +118,6 @@ func (c *Config) Scheduler() string {
return "coroutines"
}
// OptLevels returns the optimization level (0-2), size level (0-2), and inliner
// threshold as used in the LLVM optimization pipeline.
func (c *Config) OptLevels() (optLevel, sizeLevel int, inlinerThreshold uint) {
switch c.Options.Opt {
case "none", "0":
return 0, 0, 0 // -O0
case "1":
return 1, 0, 0 // -O1
case "2":
return 2, 0, 225 // -O2
case "s":
return 2, 1, 225 // -Os
case "z":
return 2, 2, 5 // -Oz, default
default:
// This is not shown to the user: valid choices are already checked as
// part of Options.Verify(). It is here as a sanity check.
panic("unknown optimization level: -opt=" + c.Options.Opt)
}
}
// FuncImplementation picks an appropriate func value implementation for the
// target.
func (c *Config) FuncImplementation() string {
@@ -184,7 +163,7 @@ func (c *Config) AutomaticStackSize() bool {
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo
// preprocessing.
func (c *Config) CFlags() []string {
var cflags []string
cflags := append([]string{}, c.Options.CFlags...)
for _, flag := range c.Target.CFlags {
cflags = append(cflags, strings.ReplaceAll(flag, "{root}", goenv.Get("TINYGOROOT")))
}
@@ -205,7 +184,7 @@ func (c *Config) CFlags() []string {
func (c *Config) LDFlags() []string {
root := goenv.Get("TINYGOROOT")
// Merge and adjust LDFlags.
var ldflags []string
ldflags := append([]string{}, c.Options.LDFlags...)
for _, flag := range c.Target.LDFlags {
ldflags = append(ldflags, strings.ReplaceAll(flag, "{root}", root))
}
+2 -10
View File
@@ -2,7 +2,6 @@ package compileopts
import (
"fmt"
"regexp"
"strings"
)
@@ -11,7 +10,6 @@ var (
validSchedulerOptions = []string{"none", "tasks", "coroutines"}
validPrintSizeOptions = []string{"none", "short", "full"}
validPanicStrategyOptions = []string{"print", "trap"}
validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
)
// Options contains extra options to give to the compiler. These options are
@@ -28,11 +26,11 @@ type Options struct {
PrintCommands bool
Debug bool
PrintSizes string
PrintAllocs *regexp.Regexp // regexp string
PrintStacks bool
CFlags []string
LDFlags []string
Tags string
WasmAbi string
GlobalValues map[string]map[string]string // map[pkgpath]map[varname]value
TestConfig TestConfig
Programmer string
}
@@ -75,12 +73,6 @@ func (o *Options) Verify() error {
}
}
if o.Opt != "" {
if !isInArray(validOptOptions, o.Opt) {
return fmt.Errorf("invalid -opt=%s: valid values are %s", o.Opt, strings.Join(validOptOptions, ", "))
}
}
return nil
}
+2
View File
@@ -31,6 +31,7 @@ type TargetSpec struct {
BuildTags []string `json:"build-tags"`
GC string `json:"gc"`
Scheduler string `json:"scheduler"`
Compiler string `json:"compiler"`
Linker string `json:"linker"`
RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt)
Libc string `json:"libc"`
@@ -243,6 +244,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
GOOS: goos,
GOARCH: goarch,
BuildTags: []string{goos, goarch},
Compiler: "clang",
Linker: "cc",
CFlags: []string{"--target=" + triple},
GDB: []string{"gdb"},
+10 -16
View File
@@ -23,7 +23,7 @@ import (
// Version of the compiler pacakge. Must be incremented each time the compiler
// package changes in a way that affects the generated LLVM module.
// This version is independent of the TinyGo version number.
const Version = 9 // last change: implement reflect.New()
const Version = 6 // last change: fix issue 1304
func init() {
llvm.InitializeAllTargets()
@@ -298,7 +298,7 @@ func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package,
c.dibuilder.Finalize()
}
return c.mod, c.diagnostics
return c.mod, nil
}
// getLLVMRuntimeType obtains a named type from the runtime package and returns
@@ -2258,20 +2258,14 @@ func (b *builder) createConst(prefix string, expr *ssa.Const) llvm.Value {
} else if typ.Info()&types.IsString != 0 {
str := constant.StringVal(expr.Value)
strLen := llvm.ConstInt(b.uintptrType, uint64(len(str)), false)
var strPtr llvm.Value
if str != "" {
objname := prefix + "$string"
global := llvm.AddGlobal(b.mod, llvm.ArrayType(b.ctx.Int8Type(), len(str)), objname)
global.SetInitializer(b.ctx.ConstString(str, false))
global.SetLinkage(llvm.InternalLinkage)
global.SetGlobalConstant(true)
global.SetUnnamedAddr(true)
global.SetAlignment(1)
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
strPtr = b.CreateInBoundsGEP(global, []llvm.Value{zero, zero}, "")
} else {
strPtr = llvm.ConstNull(b.i8ptrType)
}
objname := prefix + "$string"
global := llvm.AddGlobal(b.mod, llvm.ArrayType(b.ctx.Int8Type(), len(str)), objname)
global.SetInitializer(b.ctx.ConstString(str, false))
global.SetLinkage(llvm.InternalLinkage)
global.SetGlobalConstant(true)
global.SetUnnamedAddr(true)
zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false)
strPtr := b.CreateInBoundsGEP(global, []llvm.Value{zero, zero}, "")
strObj := llvm.ConstNamedStruct(b.getLLVMRuntimeType("_string"), []llvm.Value{strPtr, strLen})
return strObj
} else if typ.Kind() == types.UnsafePointer {
+1 -7
View File
@@ -62,7 +62,6 @@ func TestCompiler(t *testing.T) {
"string.go",
"float.go",
"interface.go",
"func.go",
}
for _, testCase := range tests {
@@ -85,16 +84,11 @@ func TestCompiler(t *testing.T) {
mod, errs := CompilePackage(testCase, pkg, program.Package(pkg.Pkg), machine, compilerConfig, false)
if errs != nil {
for _, err := range errs {
t.Error(err)
t.Log("error:", err)
}
return
}
err = llvm.VerifyModule(mod, llvm.PrintMessageAction)
if err != nil {
t.Error(err)
}
// Optimize IR a little.
funcPasses := llvm.NewFunctionPassManagerForModule(mod)
defer funcPasses.Dispose()
+3 -15
View File
@@ -25,13 +25,14 @@ func (c *compilerContext) createFuncValue(builder llvm.Builder, funcPtr, context
// Closure is: {context, function pointer}
funcValueScalar = funcPtr
case "switch":
sigGlobal := c.getTypeCode(sig)
funcValueWithSignatureGlobalName := funcPtr.Name() + "$withSignature"
funcValueWithSignatureGlobal := c.mod.NamedGlobal(funcValueWithSignatureGlobalName)
if funcValueWithSignatureGlobal.IsNil() {
funcValueWithSignatureType := c.getLLVMRuntimeType("funcValueWithSignature")
funcValueWithSignature := llvm.ConstNamedStruct(funcValueWithSignatureType, []llvm.Value{
llvm.ConstPtrToInt(funcPtr, c.uintptrType),
c.getFuncSignatureID(sig),
sigGlobal,
})
funcValueWithSignatureGlobal = llvm.AddGlobal(c.mod, funcValueWithSignatureType, funcValueWithSignatureGlobalName)
funcValueWithSignatureGlobal.SetInitializer(funcValueWithSignature)
@@ -49,19 +50,6 @@ func (c *compilerContext) createFuncValue(builder llvm.Builder, funcPtr, context
return funcValue
}
// getFuncSignatureID returns a new external global for a given signature. This
// global reference is not real, it is only used during func lowering to assign
// signature types to functions and will then be removed.
func (c *compilerContext) getFuncSignatureID(sig *types.Signature) llvm.Value {
sigGlobalName := "reflect/types.funcid:" + getTypeCodeName(sig)
sigGlobal := c.mod.NamedGlobal(sigGlobalName)
if sigGlobal.IsNil() {
sigGlobal = llvm.AddGlobal(c.mod, c.ctx.Int8Type(), sigGlobalName)
sigGlobal.SetGlobalConstant(true)
}
return sigGlobal
}
// extractFuncScalar returns some scalar that can be used in comparisons. It is
// a cheap operation.
func (b *builder) extractFuncScalar(funcValue llvm.Value) llvm.Value {
@@ -83,7 +71,7 @@ func (b *builder) decodeFuncValue(funcValue llvm.Value, sig *types.Signature) (f
funcPtr = b.CreateExtractValue(funcValue, 1, "")
case "switch":
llvmSig := b.getRawFuncType(sig)
sigGlobal := b.getFuncSignatureID(sig)
sigGlobal := b.getTypeCode(sig)
funcPtr = b.createRuntimeCall("getFuncPtr", []llvm.Value{funcValue, sigGlobal}, "")
funcPtr = b.CreateIntToPtr(funcPtr, llvmSig, "")
default:
+16 -20
View File
@@ -46,7 +46,6 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
var references llvm.Value
var length int64
var methodSet llvm.Value
var ptrTo llvm.Value
switch typ := typ.(type) {
case *types.Named:
references = c.getTypeCode(typ.Underlying())
@@ -70,25 +69,22 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
if _, ok := typ.Underlying().(*types.Interface); !ok {
methodSet = c.getTypeMethodSet(typ)
}
if _, ok := typ.Underlying().(*types.Pointer); !ok {
ptrTo = c.getTypeCode(types.NewPointer(typ))
if !references.IsNil() || length != 0 || !methodSet.IsNil() {
// Set the 'references' field of the runtime.typecodeID struct.
globalValue := llvm.ConstNull(global.Type().ElementType())
if !references.IsNil() {
globalValue = llvm.ConstInsertValue(globalValue, references, []uint32{0})
}
if length != 0 {
lengthValue := llvm.ConstInt(c.uintptrType, uint64(length), false)
globalValue = llvm.ConstInsertValue(globalValue, lengthValue, []uint32{1})
}
if !methodSet.IsNil() {
globalValue = llvm.ConstInsertValue(globalValue, methodSet, []uint32{2})
}
global.SetInitializer(globalValue)
global.SetLinkage(llvm.LinkOnceODRLinkage)
}
globalValue := llvm.ConstNull(global.Type().ElementType())
if !references.IsNil() {
globalValue = llvm.ConstInsertValue(globalValue, references, []uint32{0})
}
if length != 0 {
lengthValue := llvm.ConstInt(c.uintptrType, uint64(length), false)
globalValue = llvm.ConstInsertValue(globalValue, lengthValue, []uint32{1})
}
if !methodSet.IsNil() {
globalValue = llvm.ConstInsertValue(globalValue, methodSet, []uint32{2})
}
if !ptrTo.IsNil() {
globalValue = llvm.ConstInsertValue(globalValue, ptrTo, []uint32{3})
}
global.SetInitializer(globalValue)
global.SetLinkage(llvm.LinkOnceODRLinkage)
global.SetGlobalConstant(true)
}
return global
@@ -345,7 +341,7 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
commaOk = b.createRuntimeCall("interfaceImplements", []llvm.Value{actualTypeNum, methodSet}, "")
} else {
globalName := "reflect/types.typeid:" + getTypeCodeName(expr.AssertedType)
globalName := "reflect/types.type:" + getTypeCodeName(expr.AssertedType) + "$id"
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
if assertedTypeCodeGlobal.IsNil() {
// Create a new typecode global.
+5 -18
View File
@@ -139,17 +139,6 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value {
for _, attrName := range []string{"noalias", "nonnull"} {
llvmFn.AddAttributeAtIndex(0, c.ctx.CreateEnumAttribute(llvm.AttributeKindID(attrName), 0))
}
case "runtime.sliceAppend":
// Appending a slice will only read the to-be-appended slice, it won't
// be modified.
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
case "runtime.sliceCopy":
// Copying a slice won't capture any of the parameters.
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("writeonly"), 0))
llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
case "runtime.trackPointer":
// This function is necessary for tracking pointers on the stack in a
// portable way (see gc_stack_portable.go). Indicate to the optimizer
@@ -366,18 +355,16 @@ func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
// Set alignment from the //go:align comment.
var alignInBits uint32
alignment := c.targetData.ABITypeAlignment(llvmType)
if info.align > alignment {
alignment = info.align
}
if alignment <= 0 || alignment&(alignment-1) != 0 {
if info.align < 0 || info.align&(info.align-1) != 0 {
// Check for power-of-two (or 0).
// See: https://stackoverflow.com/a/108360
c.addError(g.Pos(), "global variable alignment must be a positive power of two")
} else {
// Set the alignment only when it is a power of two.
alignInBits = uint32(alignment) ^ uint32(alignment-1)
llvmGlobal.SetAlignment(alignment)
alignInBits = uint32(info.align) ^ uint32(info.align-1)
if info.align > c.targetData.ABITypeAlignment(llvmType) {
llvmGlobal.SetAlignment(info.align)
}
}
if c.Debug && !info.extern {
-12
View File
@@ -1,12 +0,0 @@
package main
func foo(callback func(int)) {
callback(3)
}
func bar() {
foo(someFunc)
}
func someFunc(int) {
}
-47
View File
@@ -1,47 +0,0 @@
; ModuleID = 'func.go'
source_filename = "func.go"
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 = "i686--linux"
%runtime.funcValueWithSignature = type { i32, i8* }
@"reflect/types.funcid:func:{basic:int}{}" = external constant i8
@"main.someFunc$withSignature" = linkonce_odr constant %runtime.funcValueWithSignature { i32 ptrtoint (void (i32, i8*, i8*)* @main.someFunc to i32), i8* @"reflect/types.funcid:func:{basic:int}{}" }
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret void
}
define hidden void @main.foo(i8* %callback.context, i32 %callback.funcptr, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = call i32 @runtime.getFuncPtr(i8* %callback.context, i32 %callback.funcptr, i8* nonnull @"reflect/types.funcid:func:{basic:int}{}", i8* undef, i8* null)
%1 = icmp eq i32 %0, 0
br i1 %1, label %fpcall.throw, label %fpcall.next
fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(i8* undef, i8* null)
unreachable
fpcall.next: ; preds = %entry
%2 = inttoptr i32 %0 to void (i32, i8*, i8*)*
call void %2(i32 3, i8* %callback.context, i8* undef)
ret void
}
declare i32 @runtime.getFuncPtr(i8*, i32, i8* dereferenceable_or_null(1), i8*, i8*)
declare void @runtime.nilPanic(i8*, i8*)
define hidden void @main.bar(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
call void @main.foo(i8* undef, i32 ptrtoint (%runtime.funcValueWithSignature* @"main.someFunc$withSignature" to i32), i8* undef, i8* undef)
ret void
}
define hidden void @main.someFunc(i32 %arg0, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret void
}
+10 -11
View File
@@ -3,24 +3,23 @@ source_filename = "interface.go"
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 = "i686--linux"
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo*, %runtime.typecodeID* }
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo* }
%runtime.interfaceMethodInfo = type { i8*, i32 }
%runtime._interface = type { i32, i8* }
%runtime._string = type { i8*, i32 }
@"reflect/types.type:basic:int" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* null, i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:basic:int" }
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null }
@"reflect/types.type:pointer:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:named:error", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null }
@"reflect/types.type:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:named:error" }
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{Error() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" }
@"reflect/types.type:basic:int" = linkonce_odr constant %runtime.typecodeID zeroinitializer
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i32 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.type:pointer:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:named:error", i32 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.type:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{Error() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null }
@"func Error() string" = external constant i8
@"reflect/types.interface:interface{Error() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func Error() string"]
@"reflect/types.type:pointer:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null }
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{String:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* null }
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{String() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null, %runtime.typecodeID* @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" }
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{String:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{String() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null }
@"func String() string" = external constant i8
@"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func String() string"]
@"reflect/types.typeid:basic:int" = external constant i8
@"reflect/types.type:basic:int$id" = external constant i8
@"error$interface" = linkonce_odr constant [1 x i8*] [i8* @"func Error() string"]
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
@@ -52,7 +51,7 @@ entry:
define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef, i8* null)
%typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.type:basic:int$id", i8* undef, i8* null)
br i1 %typecode, label %typeassert.ok, label %typeassert.next
typeassert.ok: ; preds = %entry
+2 -2
View File
@@ -60,7 +60,7 @@ entry:
ret { i32*, i32, i32 } %7
}
declare { i8*, i32, i32 } @runtime.sliceAppend(i8*, i8* nocapture readonly, i32, i32, i32, i32, i8*, i8*)
declare { i8*, i32, i32 } @runtime.sliceAppend(i8*, i8*, i32, i32, i32, i32, i8*, i8*)
define hidden { i32*, i32, i32 } @main.sliceAppendSlice(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32* %added.data, i32 %added.len, i32 %added.cap, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
@@ -85,4 +85,4 @@ entry:
ret i32 %copy.n
}
declare i32 @runtime.sliceCopy(i8* nocapture writeonly, i8* nocapture readonly, i32, i32, i32, i8*, i8*)
declare i32 @runtime.sliceCopy(i8*, i8*, i32, i32, i32, i8*, i8*)
-8
View File
@@ -1,13 +1,5 @@
package main
func someString() string {
return "foo"
}
func zeroLengthString() string {
return ""
}
func stringLen(s string) int {
return len(s)
}
-14
View File
@@ -3,10 +3,6 @@ source_filename = "string.go"
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 = "i686--linux"
%runtime._string = type { i8*, i32 }
@"main.someString$string" = internal unnamed_addr constant [3 x i8] c"foo", align 1
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
@@ -14,16 +10,6 @@ entry:
ret void
}
define hidden %runtime._string @main.someString(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret %runtime._string { i8* getelementptr inbounds ([3 x i8], [3 x i8]* @"main.someString$string", i32 0, i32 0), i32 3 }
}
define hidden %runtime._string @main.zeroLengthString(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret %runtime._string zeroinitializer
}
define hidden i32 @main.stringLen(i8* %s.data, i32 %s.len, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret i32 %s.len
+2 -3
View File
@@ -171,9 +171,8 @@ func getGoroot() string {
switch runtime.GOOS {
case "linux":
candidates = []string{
"/usr/local/go", // manually installed
"/usr/lib/go", // from the distribution
"/snap/go/current/", // installed using snap
"/usr/local/go", // manually installed
"/usr/lib/go", // from the distribution
}
case "darwin":
candidates = []string{
+1 -17
View File
@@ -25,7 +25,6 @@ type function struct {
// basicBlock represents a LLVM basic block and contains a slice of
// instructions. The last instruction must be a terminator instruction.
type basicBlock struct {
phiNodes []instruction
instructions []instruction
}
@@ -136,15 +135,6 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function {
default:
panic("unknown number of operands")
}
case llvm.Switch:
// A switch is an array of (value, label) pairs, of which the
// first one indicates the to-switch value and the default
// label.
numOperands := llvmInst.OperandsCount()
for i := 0; i < numOperands; i += 2 {
inst.operands = append(inst.operands, r.getValue(llvmInst.Operand(i)))
inst.operands = append(inst.operands, literalValue{uint32(blockIndices[llvmInst.Operand(i+1)])})
}
case llvm.PHI:
inst.name = llvmInst.Name()
incomingCount := inst.llvmInst.IncomingCount()
@@ -347,13 +337,7 @@ func (r *runner) compileFunction(llvmFn llvm.Value) *function {
// This error is handled when actually trying to interpret this
// instruction (to not trigger on code that won't be executed).
}
if inst.opcode == llvm.PHI {
// PHI nodes need to be treated specially, see the comment in
// interpreter.go for an explanation.
bb.phiNodes = append(bb.phiNodes, inst)
} else {
bb.instructions = append(bb.instructions, inst)
}
bb.instructions = append(bb.instructions, inst)
}
}
return fn
+1 -1
View File
@@ -13,9 +13,9 @@ import (
func TestInterp(t *testing.T) {
for _, name := range []string{
"basic",
"phi",
"slice-copy",
"consteval",
"map",
"interface",
} {
name := name // make tc local to this closure
+86 -62
View File
@@ -33,50 +33,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
lastBB := -1 // last basic block is undefined, only defined after a branch
var operands []value
for instIndex := 0; instIndex < len(bb.instructions); instIndex++ {
if instIndex == 0 {
// This is the start of a new basic block.
// There may be PHI nodes that need to be resolved. Resolve all PHI
// nodes before continuing with regular instructions.
// PHI nodes need to be treated specially because they can have a
// mutual dependency:
// for.loop:
// %a = phi i8 [ 1, %entry ], [ %b, %for.loop ]
// %b = phi i8 [ 3, %entry ], [ %a, %for.loop ]
// If these PHI nodes are processed like a regular instruction, %a
// and %b are both 3 on the second iteration of the loop because %b
// loads the value of %a from the second iteration, while it should
// load the value from the previous iteration. The correct behavior
// is that these two values swap each others place on each
// iteration.
var phiValues []value
var phiIndices []int
for _, inst := range bb.phiNodes {
var result value
for i := 0; i < len(inst.operands); i += 2 {
if int(inst.operands[i].(literalValue).value.(uint32)) == lastBB {
incoming := inst.operands[i+1]
if local, ok := incoming.(localValue); ok {
result = locals[fn.locals[local.value]]
} else {
result = incoming
}
break
}
}
if r.debug {
fmt.Fprintln(os.Stderr, indent+"phi", inst.operands, "->", result)
}
if result == nil {
panic("could not find PHI input")
}
phiValues = append(phiValues, result)
phiIndices = append(phiIndices, inst.localIndex)
}
for i, value := range phiValues {
locals[phiIndices[i]] = value
}
}
inst := bb.instructions[instIndex]
operands = operands[:0]
isRuntimeInst := false
@@ -147,24 +103,27 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
default:
panic("unknown operands length")
}
case llvm.Switch:
// Switch statement: [value, defaultLabel, case0, label0, case1, label1, ...]
value := operands[0].Uint()
targetLabel := operands[1].Uint() // default label
// Do a lazy switch by iterating over all cases.
for i := 2; i < len(operands); i += 2 {
if value == operands[i].Uint() {
targetLabel = operands[i+1].Uint()
break // continue with next block
case llvm.PHI:
var result value
for i := 0; i < len(inst.operands); i += 2 {
if int(inst.operands[i].(literalValue).value.(uint32)) == lastBB {
incoming := inst.operands[i+1]
if local, ok := incoming.(localValue); ok {
result = locals[fn.locals[local.value]]
} else {
result = incoming
}
break
}
}
lastBB = currentBB
currentBB = int(targetLabel)
bb = fn.blocks[currentBB]
instIndex = -1 // start at 0 the next cycle
if r.debug {
fmt.Fprintln(os.Stderr, indent+"switch", operands, "->", currentBB)
fmt.Fprintln(os.Stderr, indent+"phi", inst.operands, "->", result)
}
if result == nil {
panic("could not find PHI input")
}
locals[inst.localIndex] = result
case llvm.Select:
// Select is much like a ternary operator: it picks a result from
// the second and third operand based on the boolean first operand.
@@ -196,7 +155,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// which case this call won't even get to this point but will
// already be emitted in initAll.
continue
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet" || callFn.name == "os.runtime_args":
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet":
// These functions should be run at runtime. Specifically:
// * Print and panic functions are best emitted directly without
// interpreting them, otherwise we get a ton of putchar (etc.)
@@ -204,9 +163,6 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// * runtime.hashmapGet tries to access the map value directly.
// This is not possible as the map value is treated as a special
// kind of object in this package.
// * os.runtime_args reads globals that are initialized outside
// the view of the interp package so it always needs to be run
// at runtime.
err := r.runAtRuntime(fn, inst, locals, &mem, indent)
if err != nil {
return nil, mem, err
@@ -372,7 +328,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
return nil, mem, r.errorAt(inst, err)
}
actualType := actualTypePtrToInt.Operand(0)
if strings.TrimPrefix(actualType.Name(), "reflect/types.type:") == strings.TrimPrefix(assertedType.Name(), "reflect/types.typeid:") {
if actualType.Name()+"$id" == assertedType.Name() {
locals[inst.localIndex] = literalValue{uint8(1)}
} else {
locals[inst.localIndex] = literalValue{uint8(0)}
@@ -459,6 +415,74 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
return nil, mem, r.errorAt(inst, errors.New("could not find method: "+signature.Name()))
}
locals[inst.localIndex] = r.getValue(method)
case callFn.name == "runtime.hashmapMake":
// Create a new map.
hashmapPointerType := inst.llvmInst.Type()
keySize := uint32(operands[1].Uint())
valueSize := uint32(operands[2].Uint())
m := newMapValue(r, hashmapPointerType, keySize, valueSize)
alloc := object{
llvmType: hashmapPointerType,
globalName: r.pkgName + "$map",
buffer: m,
size: m.len(r),
}
index := len(r.objects)
r.objects = append(r.objects, alloc)
// Create a pointer to this map. Maps are reference types, so
// are implemented as pointers.
ptr := newPointerValue(r, index, 0)
if r.debug {
fmt.Fprintln(os.Stderr, indent+"runtime.hashmapMake:", keySize, valueSize, "->", ptr)
}
locals[inst.localIndex] = ptr
case callFn.name == "runtime.hashmapBinarySet":
// Do a mapassign operation with a binary key (that is, without
// a string key).
if r.debug {
fmt.Fprintln(os.Stderr, indent+"runtime.hashmapBinarySet:", operands[1:])
}
mapPtr, err := operands[1].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
m := mem.getWritable(mapPtr.index()).buffer.(*mapValue)
keyPtr, err := operands[2].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
valuePtr, err := operands[3].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
err = m.putBinary(&mem, keyPtr, valuePtr)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
case callFn.name == "runtime.hashmapStringSet":
// Do a mapassign operation with a string key.
if r.debug {
fmt.Fprintln(os.Stderr, indent+"runtime.hashmapBinarySet:", operands[1:])
}
mapPtr, err := operands[1].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
m := mem.getWritable(mapPtr.index()).buffer.(*mapValue)
stringPtr, err := operands[2].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
stringLen := operands[3].Uint()
valuePtr, err := operands[4].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
err = m.putString(&mem, stringPtr, stringLen, valuePtr)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
default:
if len(callFn.blocks) == 0 {
// Call to a function declaration without a definition
+282
View File
@@ -640,6 +640,288 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val
return gep, nil
}
// mapValue implements a Go map which is created at compile time and stored as a
// global variable.
// The value itself is only used as part of an object (object.buffer). Maps are
// reference types aka pointers, so it can only be used as a pointerValue, not
// directly.
type mapValue struct {
r *runner
pkgName string
size uint32 // byte size of runtime.hashmap
hashmap llvm.Value
keyIsString bool
keys []interface{} // either rawValue (for binary key) or mapStringKey (for string key)
values []rawValue
keySize uint32
valueSize uint32
}
type mapStringKey struct {
buf pointerValue
size uint64
data []uint64
}
func newMapValue(r *runner, hashmapPointerType llvm.Type, keySize, valueSize uint32) *mapValue {
size := uint32(r.targetData.TypeAllocSize(hashmapPointerType.ElementType()))
return &mapValue{
r: r,
pkgName: r.pkgName,
size: size,
keySize: keySize,
valueSize: valueSize,
}
}
func (v *mapValue) len(r *runner) uint32 {
return v.size
}
func (v *mapValue) clone() value {
// Return a copy of mapValue.
clone := *v
clone.keys = append([]interface{}{}, clone.keys...)
clone.values = append([]rawValue{}, clone.values...)
return &clone
}
func (v *mapValue) asPointer(r *runner) (pointerValue, error) {
panic("interp: mapValue.asPointer")
}
func (v *mapValue) asRawValue(r *runner) rawValue {
panic("interp: mapValue.asRawValue")
}
func (v *mapValue) Uint() uint64 {
panic("interp: mapValue.Uint")
}
func (v *mapValue) Int() int64 {
panic("interp: mapValue.Int")
}
// Temporary struct to collect data before turning this into a hashmap bucket
// LLVM value.
type mapBucket struct {
m *mapValue
tophash [8]uint8
keys []rawValue // can have up to 8 keys
values []rawValue // can have up to 8 values, len(keys) == len(values)
}
// create returns a (pointer to a) buffer structurally equivalent to
// runtime.hashmapBucket.
func (b *mapBucket) create(ctx llvm.Context, nextBucket llvm.Value, mem *memoryView) llvm.Value {
// Create tophash array.
int8Type := ctx.Int8Type()
tophashValues := make([]llvm.Value, 8)
for i := range tophashValues {
tophashValues[i] = llvm.ConstInt(int8Type, uint64(b.tophash[i]), false)
}
tophash := llvm.ConstArray(int8Type, tophashValues)
// Create next pointer (if not set).
if nextBucket.IsNil() {
nextBucket = llvm.ConstNull(llvm.PointerType(int8Type, 0))
}
// Create data for keys.
var keyValues []llvm.Value
for _, key := range b.keys {
keyValue, err := key.rawLLVMValue(mem)
if err != nil {
panic(err)
}
keyValues = append(keyValues, keyValue)
}
if len(b.keys) < 8 {
keyValues = append(keyValues, llvm.ConstNull(llvm.ArrayType(int8Type, int(b.m.keySize)*(8-len(b.keys)))))
}
keyValue := ctx.ConstStruct(keyValues, false)
if checks && uint32(b.m.r.targetData.TypeAllocSize(keyValue.Type())) != b.m.keySize*8 {
panic("key size invalid")
}
// Create data for values.
var valueValues []llvm.Value
for _, value := range b.values {
v, err := value.rawLLVMValue(mem)
if err != nil {
panic(err)
}
valueValues = append(valueValues, v)
}
if len(b.values) < 8 {
valueValues = append(valueValues, llvm.ConstNull(llvm.ArrayType(int8Type, int(b.m.valueSize)*(8-len(b.values)))))
}
valueValue := ctx.ConstStruct(valueValues, false)
if checks && uint32(b.m.r.targetData.TypeAllocSize(valueValue.Type())) != b.m.valueSize*8 {
panic("value size invalid")
}
// Create the bucket.
bucketInitializer := ctx.ConstStruct([]llvm.Value{
tophash,
nextBucket,
keyValue,
valueValue,
}, false)
bucket := llvm.AddGlobal(b.m.r.mod, bucketInitializer.Type(), b.m.pkgName+"$mapbucket")
bucket.SetInitializer(bucketInitializer)
bucket.SetLinkage(llvm.InternalLinkage)
bucket.SetUnnamedAddr(true)
return bucket
}
func (v *mapValue) toLLVMValue(hashmapType llvm.Type, mem *memoryView) (llvm.Value, error) {
if !v.hashmap.IsNil() {
return v.hashmap, nil
}
// Create a slice of buckets with all the keys and values in the hashmap.
var buckets []*mapBucket
var bucket *mapBucket
for i, key := range v.keys {
var data []uint64
var keyValue rawValue
switch key := key.(type) {
case mapStringKey:
data = key.data
keyValue = newRawValue(v.keySize)
// runtime._string is {ptr, length}
for i := uint32(0); i < v.keySize/2; i++ {
keyValue.buf[i] = key.buf.pointer
}
copy(keyValue.buf[v.keySize/2:], literalValue{key.size}.asRawValue(v.r).buf)
case rawValue:
if key.hasPointer() {
return llvm.Value{}, errors.New("interp: todo: map key with pointer")
}
data = key.buf
keyValue = key
default:
return llvm.Value{}, errors.New("interp: unknown map key type")
}
buf := make([]byte, len(data))
for i, p := range data {
buf[i] = byte(p)
}
hash := v.hash(buf)
if i%8 == 0 {
bucket = &mapBucket{m: v}
buckets = append(buckets, bucket)
}
bucket.tophash[i%8] = v.topHash(hash)
bucket.keys = append(bucket.keys, keyValue)
bucket.values = append(bucket.values, v.values[i])
}
// Convert these buckets into LLVM global variables.
ctx := v.r.mod.Context()
var nextBucket llvm.Value
for i := len(buckets) - 1; i >= 0; i-- {
bucket = buckets[i]
bucketValue := bucket.create(ctx, nextBucket, mem)
nextBucket = bucketValue
}
firstBucket := nextBucket
if firstBucket.IsNil() {
firstBucket = llvm.ConstNull(mem.r.i8ptrType)
} else {
firstBucket = llvm.ConstBitCast(firstBucket, mem.r.i8ptrType)
}
// Create the hashmap itself, pointing to these buckets.
hashmapPointerType := llvm.PointerType(hashmapType, 0)
hashmap := llvm.ConstNamedStruct(hashmapType, []llvm.Value{
llvm.ConstPointerNull(hashmapPointerType), // next
firstBucket, // buckets
llvm.ConstInt(hashmapType.StructElementTypes()[2], uint64(len(v.keys)), false), // count
llvm.ConstInt(ctx.Int8Type(), uint64(v.keySize), false), // keySize
llvm.ConstInt(ctx.Int8Type(), uint64(v.valueSize), false), // valueSize
llvm.ConstInt(ctx.Int8Type(), 0, false), // bucketBits
})
v.hashmap = hashmap
return v.hashmap, nil
}
// putString does a map assign operation, assuming that the map is of type
// map[string]T.
func (v *mapValue) putString(mem *memoryView, stringBuf pointerValue, stringLen uint64, valuePtr pointerValue) error {
if !v.hashmap.IsNil() {
return errMapAlreadyCreated
}
value := mem.load(valuePtr, v.valueSize)
stringValue := mem.load(stringBuf, uint32(stringLen)).asRawValue(v.r)
if stringValue.hasPointer() {
panic("interp: string contains pointer")
}
// TODO: avoid duplicate keys
v.keys = append(v.keys, mapStringKey{stringBuf, stringLen, stringValue.buf})
v.values = append(v.values, value.asRawValue(v.r))
v.keyIsString = true
return nil
}
// putBinary does a map assign operation for binary data (e.g. [3]int etc). The
// key must not contain pointer values.
func (v *mapValue) putBinary(mem *memoryView, keyPtr, valuePtr pointerValue) error {
if !v.hashmap.IsNil() {
return errMapAlreadyCreated
}
key := mem.load(keyPtr, v.keySize)
value := mem.load(valuePtr, v.valueSize)
// Sanity checks.
if v.keySize != key.len(mem.r) || v.valueSize != value.len(mem.r) {
// This is a bug (not unhandled input), so panic.
panic("interp: key or value size mismatch")
}
if v.keyIsString {
panic("cannot put binary keys in string map")
}
// TODO: avoid duplicate keys
v.keys = append(v.keys, key.asRawValue(v.r))
v.values = append(v.values, value.asRawValue(v.r))
return nil
}
// Get FNV-1a hash of this string.
//
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash
func (v *mapValue) hash(data []byte) uint32 {
var result uint32 = 2166136261 // FNV offset basis
for _, c := range data {
result ^= uint32(c)
result *= 16777619 // FNV prime
}
return result
}
// Get the topmost 8 bits of the hash, without using a special value (like 0).
func (v *mapValue) topHash(hash uint32) uint8 {
tophash := uint8(hash >> 24)
if tophash < 1 {
// 0 means empty slot, so make it bigger.
tophash++
}
return tophash
}
func (v *mapValue) String() string {
return "<map keySize=" + strconv.Itoa(int(v.keySize)) + " valueSize=" + strconv.Itoa(int(v.valueSize)) + ">"
}
// rawValue is a raw memory buffer that can store either pointers or regular
// data. This is the fallback data for everything that isn't clearly a
// literalValue or pointerValue.
-25
View File
@@ -65,12 +65,6 @@ entry:
call void @modifyExternal(i32* bitcast (void ()* @willModifyGlobal to i32*))
store i16 7, i16* @main.exposedValue2
; Test switch statement.
%switch1 = call i64 @testSwitch(i64 1) ; 1 returns 6
%switch2 = call i64 @testSwitch(i64 9) ; 9 returns the default value -1
call void @runtime.printint64(i64 %switch1)
call void @runtime.printint64(i64 %switch2)
ret void
}
@@ -93,22 +87,3 @@ entry:
store i16 8, i16* @main.exposedValue2
ret void
}
define i64 @testSwitch(i64 %val) {
entry:
; Test switch statement.
switch i64 %val, label %otherwise [ i64 0, label %zero
i64 1, label %one
i64 2, label %two ]
zero:
ret i64 5
one:
ret i64 6
two:
ret i64 7
otherwise:
ret i64 -1
}
-23
View File
@@ -25,8 +25,6 @@ entry:
store i16 5, i16* @main.exposedValue1
call void @modifyExternal(i32* bitcast (void ()* @willModifyGlobal to i32*))
store i16 7, i16* @main.exposedValue2
call void @runtime.printint64(i64 6)
call void @runtime.printint64(i64 -1)
ret void
}
@@ -46,24 +44,3 @@ entry:
store i16 8, i16* @main.exposedValue2
ret void
}
define i64 @testSwitch(i64 %val) local_unnamed_addr {
entry:
switch i64 %val, label %otherwise [
i64 0, label %zero
i64 1, label %one
i64 2, label %two
]
zero: ; preds = %entry
ret i64 5
one: ; preds = %entry
ret i64 6
two: ; preds = %entry
ret i64 7
otherwise: ; preds = %entry
ret i64 -1
}
+2 -2
View File
@@ -6,7 +6,7 @@ target triple = "x86_64--linux"
@main.v1 = global i1 0
@"reflect/types.type:named:main.foo" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i64 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.typeid:named:main.foo" = external constant i8
@"reflect/types.type:named:main.foo$id" = external constant i8
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
@@ -21,7 +21,7 @@ entry:
define internal void @main.init() unnamed_addr {
entry:
; Test type asserts.
%typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typecodeID* @"reflect/types.type:named:main.foo" to i64), i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
%typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typecodeID* @"reflect/types.type:named:main.foo" to i64), i8* @"reflect/types.type:named:main.foo$id", i8* undef, i8* null)
store i1 %typecode, i1* @main.v1
ret void
}
+74
View File
@@ -0,0 +1,74 @@
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "armv6m-none-eabi"
%runtime._string = type { i8*, i32 }
%runtime.hashmap = type { %runtime.hashmap*, i8*, i32, i8, i8, i8 }
@main.m = global %runtime.hashmap* null
@main.binaryMap = global %runtime.hashmap* null
@main.stringMap = global %runtime.hashmap* null
@main.init.string = internal unnamed_addr constant [7 x i8] c"CONNECT"
declare %runtime.hashmap* @runtime.hashmapMake(i8, i8, i32, i8* %context, i8* %parentHandle)
declare void @runtime.hashmapBinarySet(%runtime.hashmap*, i8*, i8*, i8* %context, i8* %parentHandle)
declare void @runtime.hashmapStringSet(%runtime.hashmap*, i8*, i32, i8*, i8* %context, i8* %parentHandle)
declare void @llvm.lifetime.end.p0i8(i64, i8*)
declare void @llvm.lifetime.start.p0i8(i64, i8*)
define void @runtime.initAll() unnamed_addr {
entry:
call void @main.init(i8* undef, i8* null)
ret void
}
define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
; Test that hashmap optimizations generally work (even with lifetimes).
%hashmap.key = alloca i8
%hashmap.value = alloca %runtime._string
%0 = call %runtime.hashmap* @runtime.hashmapMake(i8 1, i8 8, i32 1, i8* undef, i8* null)
%hashmap.value.bitcast = bitcast %runtime._string* %hashmap.value to i8*
call void @llvm.lifetime.start.p0i8(i64 8, i8* %hashmap.value.bitcast)
store %runtime._string { i8* getelementptr inbounds ([7 x i8], [7 x i8]* @main.init.string, i32 0, i32 0), i32 7 }, %runtime._string* %hashmap.value
call void @llvm.lifetime.start.p0i8(i64 1, i8* %hashmap.key)
store i8 1, i8* %hashmap.key
call void @runtime.hashmapBinarySet(%runtime.hashmap* %0, i8* %hashmap.key, i8* %hashmap.value.bitcast, i8* undef, i8* null)
call void @llvm.lifetime.end.p0i8(i64 1, i8* %hashmap.key)
call void @llvm.lifetime.end.p0i8(i64 8, i8* %hashmap.value.bitcast)
store %runtime.hashmap* %0, %runtime.hashmap** @main.m
; Other tests, that can be done in a separate function.
call void @main.testNonConstantBinarySet()
call void @main.testNonConstantStringSet()
ret void
}
; Test that a map loaded from a global can still be used for mapassign
; operations (with binary keys).
define internal void @main.testNonConstantBinarySet() {
%hashmap.key = alloca i8
%hashmap.value = alloca i8
; Create hashmap from global.
%map.new = call %runtime.hashmap* @runtime.hashmapMake(i8 1, i8 1, i32 1, i8* undef, i8* null)
store %runtime.hashmap* %map.new, %runtime.hashmap** @main.binaryMap
%map = load %runtime.hashmap*, %runtime.hashmap** @main.binaryMap
; Do the binary set to the newly loaded map.
store i8 1, i8* %hashmap.key
store i8 2, i8* %hashmap.value
call void @runtime.hashmapBinarySet(%runtime.hashmap* %map, i8* %hashmap.key, i8* %hashmap.value, i8* undef, i8* null)
ret void
}
; Test that a map loaded from a global can still be used for mapassign
; operations (with string keys).
define internal void @main.testNonConstantStringSet() {
%hashmap.value = alloca i8
; Create hashmap from global.
%map.new = call %runtime.hashmap* @runtime.hashmapMake(i8 8, i8 1, i32 1, i8* undef, i8* null)
store %runtime.hashmap* %map.new, %runtime.hashmap** @main.stringMap
%map = load %runtime.hashmap*, %runtime.hashmap** @main.stringMap
; Do the string set to the newly loaded map.
store i8 2, i8* %hashmap.value
call void @runtime.hashmapStringSet(%runtime.hashmap* %map, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @main.init.string, i32 0, i32 0), i32 7, i8* %hashmap.value, i8* undef, i8* null)
ret void
}
+20
View File
@@ -0,0 +1,20 @@
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "armv6m-none-eabi"
%runtime.hashmap = type { %runtime.hashmap*, i8*, i32, i8, i8, i8 }
@main.m = local_unnamed_addr global %runtime.hashmap* @"main$map"
@main.binaryMap = local_unnamed_addr global %runtime.hashmap* @"main$map.1"
@main.stringMap = local_unnamed_addr global %runtime.hashmap* @"main$map.3"
@main.init.string = internal unnamed_addr constant [7 x i8] c"CONNECT"
@"main$map" = internal global %runtime.hashmap { %runtime.hashmap* null, i8* getelementptr inbounds ({ [8 x i8], i8*, { i8, [7 x i8] }, { { [7 x i8]*, [4 x i8] }, [56 x i8] } }, { [8 x i8], i8*, { i8, [7 x i8] }, { { [7 x i8]*, [4 x i8] }, [56 x i8] } }* @"main$mapbucket", i32 0, i32 0, i32 0), i32 1, i8 1, i8 8, i8 0 }
@"main$mapbucket" = internal unnamed_addr global { [8 x i8], i8*, { i8, [7 x i8] }, { { [7 x i8]*, [4 x i8] }, [56 x i8] } } { [8 x i8] c"\04\00\00\00\00\00\00\00", i8* null, { i8, [7 x i8] } { i8 1, [7 x i8] zeroinitializer }, { { [7 x i8]*, [4 x i8] }, [56 x i8] } { { [7 x i8]*, [4 x i8] } { [7 x i8]* @main.init.string, [4 x i8] c"\07\00\00\00" }, [56 x i8] zeroinitializer } }
@"main$map.1" = internal global %runtime.hashmap { %runtime.hashmap* null, i8* getelementptr inbounds ({ [8 x i8], i8*, { i8, [7 x i8] }, { i8, [7 x i8] } }, { [8 x i8], i8*, { i8, [7 x i8] }, { i8, [7 x i8] } }* @"main$mapbucket.2", i32 0, i32 0, i32 0), i32 1, i8 1, i8 1, i8 0 }
@"main$mapbucket.2" = internal unnamed_addr global { [8 x i8], i8*, { i8, [7 x i8] }, { i8, [7 x i8] } } { [8 x i8] c"\04\00\00\00\00\00\00\00", i8* null, { i8, [7 x i8] } { i8 1, [7 x i8] zeroinitializer }, { i8, [7 x i8] } { i8 2, [7 x i8] zeroinitializer } }
@"main$map.3" = internal global %runtime.hashmap { %runtime.hashmap* null, i8* getelementptr inbounds ({ [8 x i8], i8*, { { [7 x i8]*, [4 x i8] }, [56 x i8] }, { i8, [7 x i8] } }, { [8 x i8], i8*, { { [7 x i8]*, [4 x i8] }, [56 x i8] }, { i8, [7 x i8] } }* @"main$mapbucket.4", i32 0, i32 0, i32 0), i32 1, i8 8, i8 1, i8 0 }
@"main$mapbucket.4" = internal unnamed_addr global { [8 x i8], i8*, { { [7 x i8]*, [4 x i8] }, [56 x i8] }, { i8, [7 x i8] } } { [8 x i8] c"x\00\00\00\00\00\00\00", i8* null, { { [7 x i8]*, [4 x i8] }, [56 x i8] } { { [7 x i8]*, [4 x i8] } { [7 x i8]* @main.init.string, [4 x i8] c"\07\00\00\00" }, [56 x i8] zeroinitializer }, { i8, [7 x i8] } { i8 2, [7 x i8] zeroinitializer } }
define void @runtime.initAll() unnamed_addr {
entry:
ret void
}
-31
View File
@@ -1,31 +0,0 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@main.phiNodesResultA = global i8 0
@main.phiNodesResultB = global i8 0
define void @runtime.initAll() {
call void @main.init()
ret void
}
; PHI nodes always use the value from the previous block, even in a loop. This
; means that the loop below should swap the values %a and %b on each iteration.
; Previously there was a bug which resulted in %b getting the value 3 on the
; second iteration while it should have gotten 1 (from the first iteration of
; %for.loop).
define internal void @main.init() {
entry:
br label %for.loop
for.loop:
%a = phi i8 [ 1, %entry ], [ %b, %for.loop ]
%b = phi i8 [ 3, %entry ], [ %a, %for.loop ]
%icmp = icmp eq i8 %a, 3
br i1 %icmp, label %for.done, label %for.loop
for.done:
store i8 %a, i8* @main.phiNodesResultA
store i8 %b, i8* @main.phiNodesResultB
ret void
}
-9
View File
@@ -1,9 +0,0 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
@main.phiNodesResultA = local_unnamed_addr global i8 3
@main.phiNodesResultB = local_unnamed_addr global i8 1
define void @runtime.initAll() local_unnamed_addr {
ret void
}
+39 -117
View File
@@ -13,13 +13,11 @@ import (
"os/exec"
"os/signal"
"path/filepath"
"regexp"
"runtime"
"strings"
"sync/atomic"
"time"
"github.com/google/shlex"
"github.com/mattn/go-colorable"
"github.com/tinygo-org/tinygo/builder"
"github.com/tinygo-org/tinygo/compileopts"
@@ -30,7 +28,6 @@ import (
"tinygo.org/x/go-llvm"
"go.bug.st/serial"
"go.bug.st/serial/enumerator"
)
var (
@@ -243,12 +240,15 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
return builder.Build(pkgName, fileExt, config, func(result builder.BuildResult) error {
// do we need port reset to put MCU into bootloader mode?
if config.Target.PortReset == "true" && flashMethod != "openocd" {
port, err := getDefaultPort(strings.FieldsFunc(port, func(c rune) bool { return c == ',' }))
if err != nil {
return err
if port == "" {
var err error
port, err = getDefaultPort()
if err != nil {
return err
}
}
err = touchSerialPortAt1200bps(port)
err := touchSerialPortAt1200bps(port)
if err != nil {
return &commandError{"failed to reset port", result.Binary, err}
}
@@ -264,9 +264,9 @@ func Flash(pkgName, port string, options *compileopts.Options) error {
fileToken := "{" + fileExt[1:] + "}"
flashCmd = strings.ReplaceAll(flashCmd, fileToken, result.Binary)
if strings.Contains(flashCmd, "{port}") {
if port == "" && strings.Contains(flashCmd, "{port}") {
var err error
port, err = getDefaultPort(strings.FieldsFunc(port, func(c rune) bool { return c == ',' }))
port, err = getDefaultPort()
if err != nil {
return err
}
@@ -665,66 +665,41 @@ func windowsFindUSBDrive(volume string, options *compileopts.Options) (string, e
}
// getDefaultPort returns the default serial port depending on the operating system.
func getDefaultPort(portCandidates []string) (port string, err error) {
if len(portCandidates) == 1 {
return portCandidates[0], nil
}
var ports []string
func getDefaultPort() (port string, err error) {
var portPath string
switch runtime.GOOS {
case "darwin":
portPath = "/dev/cu.usb*"
case "linux":
portPath = "/dev/ttyACM*"
case "freebsd":
ports, err = filepath.Glob("/dev/cuaU*")
case "darwin", "linux", "windows":
var portsList []*enumerator.PortDetails
portsList, err = enumerator.GetDetailedPortsList()
portPath = "/dev/cuaU*"
case "windows":
ports, err := serial.GetPortsList()
if err != nil {
return "", err
}
for _, p := range portsList {
ports = append(ports, p.Name)
if len(ports) == 0 {
return "", errors.New("no serial ports available")
} else if len(ports) > 1 {
return "", errors.New("multiple serial ports available - use -port flag")
}
if ports == nil || len(ports) == 0 {
// fallback
switch runtime.GOOS {
case "darwin":
ports, err = filepath.Glob("/dev/cu.usb*")
case "linux":
ports, err = filepath.Glob("/dev/ttyACM*")
case "windows":
ports, err = serial.GetPortsList()
}
}
return ports[0], nil
default:
return "", errors.New("unable to search for a default USB device to be flashed on this OS")
}
d, err := filepath.Glob(portPath)
if err != nil {
return "", err
} else if ports == nil {
}
if d == nil {
return "", errors.New("unable to locate a serial port")
} else if len(ports) == 0 {
return "", errors.New("no serial ports available")
}
if len(portCandidates) == 0 {
if len(ports) == 1 {
return ports[0], nil
} else {
return "", errors.New("multiple serial ports available - use -port flag, available ports are " + strings.Join(ports, ", "))
}
}
for _, ps := range portCandidates {
for _, p := range ports {
if p == ps {
return p, nil
}
}
}
return "", errors.New("port you specified '" + strings.Join(portCandidates, ",") + "' does not exist, available ports are " + strings.Join(ports, ", "))
return d[0], nil
}
func usage() {
@@ -837,52 +812,6 @@ func handleCompilerError(err error) {
}
}
// This is a special type for the -X flag to parse the pkgpath.Var=stringVal
// format. It has to be a special type to allow multiple variables to be defined
// this way.
type globalValuesFlag map[string]map[string]string
func (m globalValuesFlag) String() string {
return "pkgpath.Var=value"
}
func (m globalValuesFlag) Set(value string) error {
equalsIndex := strings.IndexByte(value, '=')
if equalsIndex < 0 {
return errors.New("expected format pkgpath.Var=value")
}
pathAndName := value[:equalsIndex]
pointIndex := strings.LastIndexByte(pathAndName, '.')
if pointIndex < 0 {
return errors.New("expected format pkgpath.Var=value")
}
path := pathAndName[:pointIndex]
name := pathAndName[pointIndex+1:]
stringValue := value[equalsIndex+1:]
if m[path] == nil {
m[path] = make(map[string]string)
}
m[path][name] = stringValue
return nil
}
// parseGoLinkFlag parses the -ldflags parameter. Its primary purpose right now
// is the -X flag, for setting the value of global string variables.
func parseGoLinkFlag(flagsString string) (map[string]map[string]string, error) {
set := flag.NewFlagSet("link", flag.ExitOnError)
globalVarValues := make(globalValuesFlag)
set.Var(globalVarValues, "X", "Set the value of the string variable to the given value.")
flags, err := shlex.Split(flagsString)
if err != nil {
return nil, err
}
err = set.Parse(flags)
if err != nil {
return nil, err
}
return map[string]map[string]string(globalVarValues), nil
}
func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, "No command-line arguments supplied.")
@@ -902,13 +831,13 @@ func main() {
target := flag.String("target", "", "LLVM target | .json file with TargetSpec")
printSize := flag.String("size", "", "print sizes (none, short, full)")
printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines")
printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
printCommands := flag.Bool("x", false, "Print commands")
nodebug := flag.Bool("no-debug", false, "disable DWARF debug symbol generation")
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")
programmer := flag.String("programmer", "", "which hardware programmer to use")
ldflags := flag.String("ldflags", "", "Go link tool compatible ldflags")
cFlags := flag.String("cflags", "", "additional cflags for compiler")
ldFlags := flag.String("ldflags", "", "additional ldflags for linker")
wasmAbi := flag.String("wasm-abi", "", "WebAssembly ABI conventions: js (no i64 params) or generic")
var flagJSON, flagDeps *bool
@@ -938,19 +867,6 @@ func main() {
}
flag.CommandLine.Parse(os.Args[2:])
globalVarValues, err := parseGoLinkFlag(*ldflags)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
var printAllocs *regexp.Regexp
if *printAllocsString != "" {
printAllocs, err = regexp.Compile(*printAllocsString)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
options := &compileopts.Options{
Target: *target,
Opt: *opt,
@@ -963,17 +879,23 @@ func main() {
Debug: !*nodebug,
PrintSizes: *printSize,
PrintStacks: *printStacks,
PrintAllocs: printAllocs,
PrintCommands: *printCommands,
Tags: *tags,
GlobalValues: globalVarValues,
WasmAbi: *wasmAbi,
Programmer: *programmer,
}
if *cFlags != "" {
options.CFlags = strings.Split(*cFlags, " ")
}
if *ldFlags != "" {
options.LDFlags = strings.Split(*ldFlags, " ")
}
os.Setenv("CC", "clang -target="+*target)
err = options.Verify()
err := options.Verify()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
usage()
+55 -112
View File
@@ -13,6 +13,7 @@ import (
"os/exec"
"path/filepath"
"runtime"
"sort"
"strings"
"sync"
"testing"
@@ -28,43 +29,41 @@ const TESTDATA = "testdata"
var testTarget = flag.String("target", "", "override test target")
func TestCompiler(t *testing.T) {
tests := []string{
"alias.go",
"atomic.go",
"binop.go",
"calls.go",
"cgo/",
"channel.go",
"coroutines.go",
"float.go",
"gc.go",
"init.go",
"init_multi.go",
"interface.go",
"json.go",
"map.go",
"math.go",
"print.go",
"reflect.go",
"slice.go",
"sort.go",
"stdlib.go",
"string.go",
"structs.go",
"zeroalloc.go",
matches, err := filepath.Glob(filepath.Join(TESTDATA, "*.go"))
if err != nil {
t.Fatal("could not read test files:", err)
}
dirMatches, err := filepath.Glob(filepath.Join(TESTDATA, "*", "main.go"))
if err != nil {
t.Fatal("could not read test packages:", err)
}
if len(matches) == 0 || len(dirMatches) == 0 {
t.Fatal("no test files found")
}
for _, m := range dirMatches {
matches = append(matches, filepath.Dir(m)+string(filepath.Separator))
}
sort.Strings(matches)
if *testTarget != "" {
// This makes it possible to run one specific test (instead of all),
// which is especially useful to quickly check whether some changes
// affect a particular target architecture.
runPlatTests(*testTarget, tests, t)
runPlatTests(*testTarget, matches, t)
return
}
if runtime.GOOS != "windows" {
t.Run("Host", func(t *testing.T) {
runPlatTests("", tests, t)
runPlatTests("", matches, t)
if runtime.GOOS == "darwin" {
runTest("testdata/libc/filesystem.go", "", t,
nil, nil)
runTest("testdata/libc/env.go", "", t,
[]string{"ENV1=VALUE1", "ENV2=VALUE2"}, nil)
}
})
}
@@ -73,26 +72,26 @@ func TestCompiler(t *testing.T) {
}
t.Run("EmulatedCortexM3", func(t *testing.T) {
runPlatTests("cortex-m-qemu", tests, t)
runPlatTests("cortex-m-qemu", matches, t)
})
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
// Note: running only on Windows and macOS because Linux (as of 2020)
// usually has an outdated QEMU version that doesn't support RISC-V yet.
t.Run("EmulatedRISCV", func(t *testing.T) {
runPlatTests("riscv-qemu", tests, t)
runPlatTests("riscv-qemu", matches, t)
})
}
if runtime.GOOS == "linux" {
t.Run("X86Linux", func(t *testing.T) {
runPlatTests("i386--linux-gnu", tests, t)
runPlatTests("i386--linux-gnu", matches, t)
})
t.Run("ARMLinux", func(t *testing.T) {
runPlatTests("arm--linux-gnueabihf", tests, t)
runPlatTests("arm--linux-gnueabihf", matches, t)
})
t.Run("ARM64Linux", func(t *testing.T) {
runPlatTests("aarch64--linux-gnu", tests, t)
runPlatTests("aarch64--linux-gnu", matches, t)
})
goVersion, err := goenv.GorootVersionString(goenv.Get("GOROOT"))
if err != nil {
@@ -105,72 +104,27 @@ func TestCompiler(t *testing.T) {
// below that are also not supported but still seem to pass, so
// include them in the tests for now.
t.Run("WebAssembly", func(t *testing.T) {
runPlatTests("wasm", tests, t)
runPlatTests("wasm", matches, t)
})
}
t.Run("WASI", func(t *testing.T) {
runPlatTests("wasi", tests, t)
runPlatTests("wasi", matches, t)
runTest("testdata/libc/env.go", "wasi", t,
[]string{"--env", "ENV1=VALUE1", "--env", "ENV2=VALUE2"}, nil)
runTest("testdata/libc/filesystem.go", "wasi", t, nil, []string{"--dir=."})
})
}
// Test a few build options.
t.Run("build-options", func(t *testing.T) {
if runtime.GOOS == "windows" {
// These tests assume a host that is supported by TinyGo.
t.Skip("can't test build options on Windows")
}
t.Parallel()
// Test with few optimizations enabled (no inlining, etc).
t.Run("opt=1", func(t *testing.T) {
t.Parallel()
runTestWithConfig("stdlib.go", "", t, &compileopts.Options{
Opt: "1",
}, nil, nil)
})
// Test with only the bare minimum of optimizations enabled.
// TODO: fix this for stdlib.go, which currently fails.
t.Run("opt=0", func(t *testing.T) {
t.Parallel()
runTestWithConfig("print.go", "", t, &compileopts.Options{
Opt: "0",
}, nil, nil)
})
t.Run("ldflags", func(t *testing.T) {
t.Parallel()
runTestWithConfig("ldflags.go", "", t, &compileopts.Options{
Opt: "z",
GlobalValues: map[string]map[string]string{
"main": {
"someGlobal": "foobar",
},
},
}, nil, nil)
})
})
}
func runPlatTests(target string, tests []string, t *testing.T) {
func runPlatTests(target string, matches []string, t *testing.T) {
t.Parallel()
for _, name := range tests {
name := name // redefine to avoid race condition
t.Run(name, func(t *testing.T) {
for _, path := range matches {
path := path // redefine to avoid race condition
t.Run(filepath.Base(path), func(t *testing.T) {
t.Parallel()
runTest(name, target, t, nil, nil)
})
}
if target == "wasi" || target == "" {
t.Run("filesystem.go", func(t *testing.T) {
t.Parallel()
runTest("filesystem.go", target, t, nil, nil)
})
t.Run("env.go", func(t *testing.T) {
t.Parallel()
runTest("env.go", target, t, []string{"first", "second"}, []string{"ENV1=VALUE1", "ENV2=VALUE2"})
runTest(path, target, t, nil, nil)
})
}
}
@@ -187,28 +141,10 @@ func runBuild(src, out string, opts *compileopts.Options) error {
return Build(src, out, opts)
}
func runTest(name, target string, t *testing.T, cmdArgs, environmentVars []string) {
options := &compileopts.Options{
Target: target,
Opt: "z",
PrintIR: false,
DumpSSA: false,
VerifyIR: true,
Debug: true,
PrintSizes: "",
WasmAbi: "",
}
runTestWithConfig(name, target, t, options, cmdArgs, environmentVars)
}
func runTestWithConfig(name, target string, t *testing.T, options *compileopts.Options, cmdArgs, environmentVars []string) {
// Get the expected output for this test.
// Note: not using filepath.Join as it strips the path separator at the end
// of the path.
path := TESTDATA + "/" + name
func runTest(path, target string, t *testing.T, environmentVars []string, additionalArgs []string) {
// Get the expected output for this test.
txtpath := path[:len(path)-3] + ".txt"
if path[len(path)-1] == '/' {
if path[len(path)-1] == os.PathSeparator {
txtpath = path + "out.txt"
}
expected, err := ioutil.ReadFile(txtpath)
@@ -229,8 +165,19 @@ func runTestWithConfig(name, target string, t *testing.T, options *compileopts.O
}()
// Build the test binary.
config := &compileopts.Options{
Target: target,
Opt: "z",
PrintIR: false,
DumpSSA: false,
VerifyIR: true,
Debug: true,
PrintSizes: "",
WasmAbi: "",
}
binary := filepath.Join(tmpdir, "test")
err = runBuild("./"+path, binary, options)
err = runBuild("./"+path, binary, config)
if err != nil {
printCompilerError(t.Log, err)
t.Fail()
@@ -244,7 +191,6 @@ func runTestWithConfig(name, target string, t *testing.T, options *compileopts.O
if target == "" {
cmd = exec.Command(binary)
cmd.Env = append(cmd.Env, environmentVars...)
cmd.Args = append(cmd.Args, cmdArgs...)
} else {
spec, err := compileopts.LoadTarget(target)
if err != nil {
@@ -254,16 +200,13 @@ func runTestWithConfig(name, target string, t *testing.T, options *compileopts.O
cmd = exec.Command(binary)
} else {
args := append(spec.Emulator[1:], binary)
cmd = exec.Command(spec.Emulator[0], args...)
cmd = exec.Command(spec.Emulator[0], append(args, additionalArgs...)...)
}
if len(spec.Emulator) != 0 && spec.Emulator[0] == "wasmtime" {
// Allow reading from the current directory.
cmd.Args = append(cmd.Args, "--dir=.")
for _, v := range environmentVars {
cmd.Args = append(cmd.Args, "--env", v)
}
cmd.Args = append(cmd.Args, cmdArgs...)
} else {
cmd.Env = append(cmd.Env, environmentVars...)
}
-71
View File
@@ -1,71 +0,0 @@
// Hand created file. DO NOT DELETE.
// atsamd51x bitfield definitions that are not auto-generated by gen-device-svd.go
// +build sam,atsame5x
// These are the supported pchctrl function numberings on the atsamd51x
// See http://ww1.microchip.com/downloads/en/DeviceDoc/SAM_D5xE5x_Family_Data_Sheet_DS60001507F.pdf
// table 14-9
package sam
const (
PCHCTRL_GCLK_OSCCTRL_DFLL48 = 0 // DFLL48 input clock source
PCHCTRL_GCLK_OSCCTRL_FDPLL0 = 1 // Reference clock for FDPLL0
PCHCTRL_GCLK_OSCCTRL_FDPLL1 = 2 // Reference clock for FDPLL1
PCHCTRL_GCLK_OSCCTRL_FDPLL0_32K = 3 // FDPLL0 = 3 // 32KHz clock for internal lock timer
PCHCTRL_GCLK_OSCCTRL_FDPLL1_32K = 3 // FDPLL1 = 3 // 32KHz clock for internal lock timer
PCHCTRL_GCLK_SDHC0_SLOW = 3 // SDHC0 = 3 // Slow
PCHCTRL_GCLK_SDHC1_SLOW = 3 // SDHC1 = 3 // Slow
PCHCTRL_GCLK_SERCOMX_SLOW = 3 // GCLK_SERCOM[0..7]_SLOW = 3
PCHCTRL_GCLK_EIC = 4
PCHCTRL_GCLK_FREQM_MSR = 5 // FREQM Measure
PCHCTRL_GCLK_FREQM_REF = 6 // FREQM Reference
PCHCTRL_GCLK_SERCOM0_CORE = 7 // SERCOM0 Core
PCHCTRL_GCLK_SERCOM1_CORE = 8 // SERCOM1 Core
PCHCTRL_GCLK_TC0 = 9
PCHCTRL_GCLK_TC1 = 9 // TC0, TC1
PCHCTRL_GCLK_USB = 10 // USB
PCHCTRL_GCLK_EVSYS0 = 11
PCHCTRL_GCLK_EVSYS1 = 12
PCHCTRL_GCLK_EVSYS2 = 13
PCHCTRL_GCLK_EVSYS3 = 14
PCHCTRL_GCLK_EVSYS4 = 15
PCHCTRL_GCLK_EVSYS5 = 16
PCHCTRL_GCLK_EVSYS6 = 17
PCHCTRL_GCLK_EVSYS7 = 18
PCHCTRL_GCLK_EVSYS8 = 19
PCHCTRL_GCLK_EVSYS9 = 20
PCHCTRL_GCLK_EVSYS10 = 21
PCHCTRL_GCLK_EVSYS11 = 22
PCHCTRL_GCLK_SERCOM2_CORE = 23 // SERCOM2 Core
PCHCTRL_GCLK_SERCOM3_CORE = 24 // SERCOM3 Core
PCHCTRL_GCLK_TCC0 = 25
PCHCTRL_GCLK_TCC1 = 25 // TCC0, TCC1
PCHCTRL_GCLK_TC2 = 26
PCHCTRL_GCLK_TC3 = 26 // TC2, TC3
PCHCTRL_GCLK_CAN0 = 27 // CAN0
PCHCTRL_GCLK_CAN1 = 28 // CAN1
PCHCTRL_GCLK_TCC2 = 29
PCHCTRL_GCLK_TCC3 = 29 // TCC2, TCC3
PCHCTRL_GCLK_TC4 = 30
PCHCTRL_GCLK_TC5 = 30 // TC4, TC5
PCHCTRL_GCLK_PDEC = 31 // PDEC
PCHCTRL_GCLK_AC = 32 // AC
PCHCTRL_GCLK_CCL = 33 // CCL
PCHCTRL_GCLK_SERCOM4_CORE = 34 // SERCOM4 Core
PCHCTRL_GCLK_SERCOM5_CORE = 35 // SERCOM5 Core
PCHCTRL_GCLK_SERCOM6_CORE = 36 // SERCOM6 Core
PCHCTRL_GCLK_SERCOM7_CORE = 37 // SERCOM7 Core
PCHCTRL_GCLK_TCC4 = 38 // TCC4
PCHCTRL_GCLK_TC6 = 39
PCHCTRL_GCLK_TC7 = 39 // TC6, TC7
PCHCTRL_GCLK_ADC0 = 40 // ADC0
PCHCTRL_GCLK_ADC1 = 41 // ADC1
PCHCTRL_GCLK_DAC = 42 // DAC
PCHCTRL_GCLK_I2S0 = 43
PCHCTRL_GCLK_I2S1 = 44
PCHCTRL_GCLK_SDHC0 = 45 // SDHC0
PCHCTRL_GCLK_SDHC1 = 46 // SDHC1
PCHCTRL_GCLK_CM4_TRACE = 47 // CM4 Trace
)
-12
View File
@@ -1,12 +0,0 @@
// +build arduino_mega1280
package main
import "machine"
var (
// Configuration on an Arduino Uno.
pwm = machine.Timer3
pinA = machine.PH3 // pin 6 on the Mega
pinB = machine.PH4 // pin 7 on the Mega
)
-104
View File
@@ -1,104 +0,0 @@
// +build arduino_mega1280
package machine
// Return the current CPU frequency in hertz.
func CPUFrequency() uint32 {
return 16000000
}
const (
AREF Pin = NoPin
LED Pin = PB7
A0 Pin = PF0
A1 Pin = PF1
A2 Pin = PF2
A3 Pin = PF3
A4 Pin = PF4
A5 Pin = PF5
A6 Pin = PF6
A7 Pin = PF7
A8 Pin = PK0
A9 Pin = PK1
A10 Pin = PK2
A11 Pin = PK3
A12 Pin = PK4
A13 Pin = PK5
A14 Pin = PK6
A15 Pin = PK7
// Analog Input
ADC0 Pin = PF0
ADC1 Pin = PF1
ADC2 Pin = PF2
ADC3 Pin = PF3
ADC4 Pin = PF4
ADC5 Pin = PF5
ADC6 Pin = PF6
ADC7 Pin = PF7
ADC8 Pin = PK0
ADC9 Pin = PK1
ADC10 Pin = PK2
ADC11 Pin = PK3
ADC12 Pin = PK4
ADC13 Pin = PK5
ADC14 Pin = PK6
ADC15 Pin = PK7
// Digital pins
D0 Pin = PE0
D1 Pin = PE1
D2 Pin = PE4
D3 Pin = PE5
D4 Pin = PG5
D5 Pin = PE3
D6 Pin = PH3
D7 Pin = PH4
D8 Pin = PH5
D9 Pin = PH6
D10 Pin = PB4
D11 Pin = PB5
D12 Pin = PB6
D13 Pin = PB7
D14 Pin = PJ1
D15 Pin = PJ0
D16 Pin = PH1
D17 Pin = PH0
D18 Pin = PD3
D19 Pin = PD2
D20 Pin = PD1
D21 Pin = PD0
D22 Pin = PA0
D23 Pin = PA1
D24 Pin = PA2
D25 Pin = PA3
D26 Pin = PA4
D27 Pin = PA5
D28 Pin = PA6
D29 Pin = PA7
D30 Pin = PC7
D31 Pin = PC6
D32 Pin = PC5
D33 Pin = PC4
D34 Pin = PC3
D35 Pin = PC2
D36 Pin = PC1
D37 Pin = PC0
D38 Pin = PD7
D39 Pin = PG2
D40 Pin = PG1
D41 Pin = PG0
D42 Pin = PL7
D43 Pin = PL6
D44 Pin = PL5
D45 Pin = PL4
D46 Pin = PL3
D47 Pin = PL2
D48 Pin = PL1
D49 Pin = PL0
D50 Pin = PB3
D51 Pin = PB2
D52 Pin = PB1
D53 Pin = PB0
)
-330
View File
@@ -1,330 +0,0 @@
// +build atsame54_xpro
package machine
import (
"device/sam"
"runtime/interrupt"
)
// Definition for compatibility, but not used
const RESET_MAGIC_VALUE = 0x00000000
const (
LED = PC18
BUTTON = PB31
)
const (
// https://ww1.microchip.com/downloads/en/DeviceDoc/70005321A.pdf
// Extension Header EXT1
EXT1_PIN3_ADC_P = PB04
EXT1_PIN4_ADC_N = PB05
EXT1_PIN5_GPIO1 = PA06
EXT1_PIN6_GPIO2 = PA07
EXT1_PIN7_PWM_P = PB08
EXT1_PIN8_PWM_N = PB09
EXT1_PIN9_IRQ = PB07
EXT1_PIN9_GPIO = PB07
EXT1_PIN10_SPI_SS_B = PA27
EXT1_PIN10_GPIO = PA27
EXT1_PIN11_TWI_SDA = PA22
EXT1_PIN12_TWI_SCL = PA23
EXT1_PIN13_UART_RX = PA05
EXT1_PIN14_UART_TX = PA04
EXT1_PIN15_SPI_SS_A = PB28
EXT1_PIN16_SPI_SDO = PB27
EXT1_PIN17_SPI_SDI = PB29
EXT1_PIN18_SPI_SCK = PB26
// Extension Header EXT2
EXT2_PIN3_ADC_P = PB00
EXT2_PIN4_ADC_N = PA03
EXT2_PIN5_GPIO1 = PB01
EXT2_PIN6_GPIO2 = PB06
EXT2_PIN7_PWM_P = PB14
EXT2_PIN8_PWM_N = PB15
EXT2_PIN9_IRQ = PD00
EXT2_PIN9_GPIO = PD00
EXT2_PIN10_SPI_SS_B = PB02
EXT2_PIN10_GPIO = PB02
EXT2_PIN11_TWI_SDA = PD08
EXT2_PIN12_TWI_SCL = PD09
EXT2_PIN13_UART_RX = PB17
EXT2_PIN14_UART_TX = PB16
EXT2_PIN15_SPI_SS_A = PC06
EXT2_PIN16_SPI_SDO = PC04
EXT2_PIN17_SPI_SDI = PC07
EXT2_PIN18_SPI_SCK = PC05
// Extension Header EXT3
EXT3_PIN3_ADC_P = PC02
EXT3_PIN4_ADC_N = PC03
EXT3_PIN5_GPIO1 = PC01
EXT3_PIN6_GPIO2 = PC10
EXT3_PIN7_PWM_P = PD10
EXT3_PIN8_PWM_N = PD11
EXT3_PIN9_IRQ = PC30
EXT3_PIN9_GPIO = PC30
EXT3_PIN10_SPI_SS_B = PC31
EXT3_PIN10_GPIO = PC31
EXT3_PIN11_TWI_SDA = PD08
EXT3_PIN12_TWI_SCL = PD09
EXT3_PIN13_UART_RX = PC23
EXT3_PIN14_UART_TX = PC22
EXT3_PIN15_SPI_SS_A = PC14
EXT3_PIN16_SPI_SDO = PC04
EXT3_PIN17_SPI_SDI = PC07
EXT3_PIN18_SPI_SCK = PC05
// SD_CARD
SD_CARD_MCDA0 = PB18
SD_CARD_MCDA1 = PB19
SD_CARD_MCDA2 = PB20
SD_CARD_MCDA3 = PB21
SD_CARD_MCCK = PA21
SD_CARD_MCCDA = PA20
SD_CARD_DETECT = PD20
SD_CARD_PROTECT = PD21
// I2C
I2C_SDA = PD08
I2C_SCL = PD09
// CAN
CAN0_TX = PA22
CAN0_RX = PA23
CAN1_STANDBY = PC13
CAN1_TX = PB12
CAN1_RX = PB13
CAN_STANDBY = CAN1_STANDBY
CAN_TX = CAN1_TX
CAN_RX = CAN1_RX
// PDEC
PDEC_PHASE_A = PC16
PDEC_PHASE_B = PC17
PDEC_INDEX = PC18
// PCC
PCC_I2C_SDA = PD08
PCC_I2C_SCL = PD09
PCC_VSYNC_DEN1 = PA12
PCC_HSYNC_DEN2 = PA13
PCC_CLK = PA14
PCC_XCLK = PA15
PCC_DATA00 = PA16
PCC_DATA01 = PA17
PCC_DATA02 = PA18
PCC_DATA03 = PA19
PCC_DATA04 = PA20
PCC_DATA05 = PA21
PCC_DATA06 = PA22
PCC_DATA07 = PA23
PCC_DATA08 = PB14
PCC_DATA09 = PB15
PCC_RESET = PC12
PCC_PWDN = PC11
// Ethernet
ETHERNET_TXCK = PA14
ETHERNET_TXEN = PA17
ETHERNET_TX0 = PA18
ETHERNET_TX1 = PA19
ETHERNET_RXER = PA15
ETHERNET_RX0 = PA13
ETHERNET_RX1 = PA12
ETHERNET_RXDV = PC20
ETHERNET_MDIO = PC12
ETHERNET_MDC = PC11
ETHERNET_INT = PD12
ETHERNET_RESET = PC21
PIN_QT_BUTTON = PA16
PIN_BTN0 = PB31
PIN_ETH_LED = PC15
PIN_LED0 = PC18
PIN_ADC_DAC = PA02
PIN_VBUS_DETECT = PC00
PIN_USB_ID = PC19
)
// UART0 aka USBCDC pins
const (
USBCDC_DM_PIN = PA24
USBCDC_DP_PIN = PA25
)
// UART pins
const (
// Extension Header EXT1
UART_TX_PIN = PA04 // TX : SERCOM0/PAD[0]
UART_RX_PIN = PA05 // RX : SERCOM0/PAD[1]
// Extension Header EXT2
UART2_TX_PIN = PB16 // TX : SERCOM5/PAD[0]
UART2_RX_PIN = PB17 // RX : SERCOM5/PAD[1]
// Extension Header EXT3
UART3_TX_PIN = PC22 // TX : SERCOM1/PAD[0]
UART3_RX_PIN = PC23 // RX : SERCOM1/PAD[1]
// Virtual COM Port
UART4_TX_PIN = PB25 // TX : SERCOM2/PAD[0]
UART4_RX_PIN = PB24 // RX : SERCOM2/PAD[1]
)
// I2C pins
const (
// Extension Header EXT1
SDA0_PIN = PA22 // SDA: SERCOM3/PAD[0]
SCL0_PIN = PA23 // SCL: SERCOM3/PAD[1]
// Extension Header EXT2
SDA1_PIN = PD08 // SDA: SERCOM7/PAD[0]
SCL1_PIN = PD09 // SCL: SERCOM7/PAD[1]
// Extension Header EXT3
SDA2_PIN = PD08 // SDA: SERCOM7/PAD[0]
SCL2_PIN = PD09 // SCL: SERCOM7/PAD[1]
// Data Gateway Interface
SDA_DGI_PIN = PD08 // SDA: SERCOM7/PAD[0]
SCL_DGI_PIN = PD09 // SCL: SERCOM7/PAD[1]
SDA_PIN = SDA0_PIN
SCL_PIN = SCL0_PIN
)
// SPI pins
const (
// Extension Header EXT1
SPI0_SCK_PIN = PB26 // SCK: SERCOM4/PAD[1]
SPI0_SDO_PIN = PB27 // SDO: SERCOM4/PAD[0]
SPI0_SDI_PIN = PB29 // SDI: SERCOM4/PAD[3]
SPI0_SS_PIN = PB28 // SS : SERCOM4/PAD[2]
// Extension Header EXT2
SPI1_SCK_PIN = PC05 // SCK: SERCOM6/PAD[1]
SPI1_SDO_PIN = PC04 // SDO: SERCOM6/PAD[0]
SPI1_SDI_PIN = PC07 // SDI: SERCOM6/PAD[3]
SPI1_SS_PIN = PC06 // SS : SERCOM6/PAD[2]
// Extension Header EXT3
SPI2_SCK_PIN = PC05 // SCK: SERCOM6/PAD[1]
SPI2_SDO_PIN = PC04 // SDO: SERCOM6/PAD[0]
SPI2_SDI_PIN = PC07 // SDI: SERCOM6/PAD[3]
SPI2_SS_PIN = PC14 // SS : GPIO
// Data Gateway Interface
SPI_DGI_SCK_PIN = PC05 // SCK: SERCOM6/PAD[1]
SPI_DGI_SDO_PIN = PC04 // SDO: SERCOM6/PAD[0]
SPI_DGI_SDI_PIN = PC07 // SDI: SERCOM6/PAD[3]
SPI_DGI_SS_PIN = PD01 // SS : GPIO
)
// USB CDC identifiers
const (
usb_STRING_PRODUCT = "SAM E54 Xplained Pro"
usb_STRING_MANUFACTURER = "Atmel"
)
var (
usb_VID uint16 = 0x03EB
usb_PID uint16 = 0x2404
)
// UART on the SAM E54 Xplained Pro
var (
// Extension Header EXT1
UART1 = UART{
Buffer: NewRingBuffer(),
Bus: sam.SERCOM0_USART_INT,
SERCOM: 0,
}
// Extension Header EXT2
UART2 = UART{
Buffer: NewRingBuffer(),
Bus: sam.SERCOM5_USART_INT,
SERCOM: 5,
}
// Extension Header EXT3
UART3 = UART{
Buffer: NewRingBuffer(),
Bus: sam.SERCOM1_USART_INT,
SERCOM: 1,
}
// EDBG Virtual COM Port
UART4 = UART{
Buffer: NewRingBuffer(),
Bus: sam.SERCOM2_USART_INT,
SERCOM: 2,
}
)
func init() {
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, UART1.handleInterrupt)
UART2.Interrupt = interrupt.New(sam.IRQ_SERCOM5_2, UART2.handleInterrupt)
UART3.Interrupt = interrupt.New(sam.IRQ_SERCOM1_2, UART3.handleInterrupt)
UART4.Interrupt = interrupt.New(sam.IRQ_SERCOM2_2, UART4.handleInterrupt)
}
// I2C on the SAM E54 Xplained Pro
var (
// Extension Header EXT1
I2C0 = I2C{
Bus: sam.SERCOM3_I2CM,
SERCOM: 3,
}
// Extension Header EXT2
I2C1 = I2C{
Bus: sam.SERCOM7_I2CM,
SERCOM: 7,
}
// Extension Header EXT3
I2C2 = I2C{
Bus: sam.SERCOM7_I2CM,
SERCOM: 7,
}
// Data Gateway Interface
I2C3 = I2C{
Bus: sam.SERCOM7_I2CM,
SERCOM: 7,
}
)
// SPI on the SAM E54 Xplained Pro
var (
// Extension Header EXT1
SPI0 = SPI{
Bus: sam.SERCOM4_SPIM,
SERCOM: 4,
}
// Extension Header EXT2
SPI1 = SPI{
Bus: sam.SERCOM6_SPIM,
SERCOM: 6,
}
// Extension Header EXT3
SPI2 = SPI{
Bus: sam.SERCOM6_SPIM,
SERCOM: 6,
}
// Data Gateway Interface
SPI3 = SPI{
Bus: sam.SERCOM6_SPIM,
SERCOM: 6,
}
)
-142
View File
@@ -1,142 +0,0 @@
// +build feather_m4_can
package machine
import (
"device/sam"
"runtime/interrupt"
)
// used to reset into bootloader
const RESET_MAGIC_VALUE = 0xf01669ef
// GPIO Pins
const (
D0 = PB17 // UART0 RX/PWM available
D1 = PB16 // UART0 TX/PWM available
D4 = PA14 // PWM available
D5 = PA16 // PWM available
D6 = PA18 // PWM available
D7 = PB03 // neopixel power
D8 = PB02 // built-in neopixel
D9 = PA19 // PWM available
D10 = PA20 // can be used for PWM or UART1 TX
D11 = PA21 // can be used for PWM or UART1 RX
D12 = PA22 // PWM available
D13 = PA23 // PWM available
D21 = PA13 // PWM available
D22 = PA12 // PWM available
D23 = PB22 // PWM available
D24 = PB23 // PWM available
D25 = PA17 // PWM available
)
// Analog pins
const (
A0 = PA02 // ADC/AIN[0]
A1 = PA05 // ADC/AIN[2]
A2 = PB08 // ADC/AIN[3]
A3 = PB09 // ADC/AIN[4]
A4 = PA04 // ADC/AIN[5]
A5 = PA06 // ADC/AIN[10]
)
const (
LED = D13
NEOPIXELS = D8
)
// UART0 aka USBCDC pins
const (
USBCDC_DM_PIN = PA24
USBCDC_DP_PIN = PA25
)
const (
UART_TX_PIN = D1
UART_RX_PIN = D0
)
const (
UART2_TX_PIN = A4
UART2_RX_PIN = A5
)
// I2C pins
const (
SDA_PIN = D22 // SDA: SERCOM2/PAD[0]
SCL_PIN = D21 // SCL: SERCOM2/PAD[1]
)
// SPI pins
const (
SPI0_SCK_PIN = D25 // SCK: SERCOM1/PAD[1]
SPI0_SDO_PIN = D24 // SDO: SERCOM1/PAD[3]
SPI0_SDI_PIN = D23 // SDI: SERCOM1/PAD[2]
)
// CAN pins
const (
CAN0_TX = PA22
CAN0_RX = PA23
CAN1_STANDBY = PB12
CAN1_TX = PB14
CAN1_RX = PB15
BOOST_EN = PB13 // power control of CAN1's TCAN1051HGV (H: enable)
CAN_STANDBY = CAN1_STANDBY
CAN_S = CAN1_STANDBY
CAN_TX = CAN1_TX
CAN_RX = CAN1_RX
)
// USB CDC identifiers
const (
usb_STRING_PRODUCT = "Adafruit Feather M4 CAN"
usb_STRING_MANUFACTURER = "Adafruit"
)
var (
usb_VID uint16 = 0x239A
usb_PID uint16 = 0x80CD
)
var (
UART1 = UART{
Buffer: NewRingBuffer(),
Bus: sam.SERCOM5_USART_INT,
SERCOM: 5,
}
UART2 = UART{
Buffer: NewRingBuffer(),
Bus: sam.SERCOM0_USART_INT,
SERCOM: 0,
}
)
func init() {
UART1.Interrupt = interrupt.New(sam.IRQ_SERCOM5_2, UART1.handleInterrupt)
UART2.Interrupt = interrupt.New(sam.IRQ_SERCOM0_2, UART2.handleInterrupt)
// turn on neopixel
D7.Configure(PinConfig{Mode: PinOutput})
D7.High()
}
// I2C on the Feather M4.
var (
I2C0 = &I2C{
Bus: sam.SERCOM2_I2CM,
SERCOM: 2,
}
)
// SPI on the Feather M4.
var (
SPI0 = SPI{
Bus: sam.SERCOM1_SPIM,
SERCOM: 1,
}
)
+5
View File
@@ -5,6 +5,11 @@ package machine
// The micro:bit does not have a 32kHz crystal on board.
const HasLowFrequencyCrystal = false
const (
LED = P13
LED1 = LED
)
// Buttons on the micro:bit v2 (A and B)
const (
BUTTON Pin = BUTTONA
+6 -44
View File
@@ -13,53 +13,20 @@ const (
LED_GREEN = PB3
)
// UART pins
const (
// Arduino Pins
A0 = PA0
A1 = PA1
A2 = PA3
A3 = PA4
A4 = PA5
A5 = PA6
A6 = PA7
A7 = PA2
D0 = PA10
D1 = PA9
D2 = PA12
D3 = PB0
D4 = PB7
D5 = PB6
D6 = PB1
D7 = PC14
D8 = PC15
D9 = PA8
D10 = PA11
D11 = PB5
D12 = PB4
D13 = PB3
)
const (
// UART pins
// PA2 and PA15 are connected to the ST-Link Virtual Com Port (VCP)
UART_TX_PIN = PA2
UART_RX_PIN = PA15
)
// I2C pins
// I2C pins
const (
// With default solder bridge settings:
// PB6 / Arduino D5 / CN3 Pin 8 is SCL
// PB7 / Arduino D4 / CN3 Pin 7 is SDA
I2C0_SCL_PIN = PB6
I2C0_SDA_PIN = PB7
// SPI pins
SPI1_SCK_PIN = PB3
SPI1_SDI_PIN = PB5
SPI1_SDO_PIN = PB4
SPI0_SCK_PIN = SPI1_SCK_PIN
SPI0_SDI_PIN = SPI1_SDI_PIN
SPI0_SDO_PIN = SPI1_SDO_PIN
)
var (
@@ -73,20 +40,15 @@ var (
RxAltFuncSelector: 3,
}
UART1 = &UART0
)
var (
// I2C1 is documented, alias to I2C0 as well
I2C1 = &I2C{
Bus: stm32.I2C1,
AltFuncSelector: 4,
}
I2C0 = I2C1
// SPI1 is documented, alias to SPI0 as well
SPI1 = &SPI{
Bus: stm32.SPI1,
AltFuncSelector: 5,
}
SPI0 = SPI1
)
func init() {
-931
View File
@@ -1,931 +0,0 @@
// +build avr,atmega1280
package machine
import (
"device/avr"
"runtime/interrupt"
"runtime/volatile"
)
const irq_USART0_RX = avr.IRQ_USART0_RX
const (
portA Pin = iota * 8
portB
portC
portD
portE
portF
portG
portH
portJ
portK
portL
)
const (
PA0 = portA + 0
PA1 = portA + 1
PA2 = portA + 2
PA3 = portA + 3
PA4 = portA + 4
PA5 = portA + 5
PA6 = portA + 6
PA7 = portA + 7
PB0 = portB + 0
PB1 = portB + 1
PB2 = portB + 2
PB3 = portB + 3
PB4 = portB + 4
PB5 = portB + 5
PB6 = portB + 6
PB7 = portB + 7
PC0 = portC + 0
PC1 = portC + 1
PC2 = portC + 2
PC3 = portC + 3
PC4 = portC + 4
PC5 = portC + 5
PC6 = portC + 6
PC7 = portC + 7
PD0 = portD + 0
PD1 = portD + 1
PD2 = portD + 2
PD3 = portD + 3
PD7 = portD + 7
PE0 = portE + 0
PE1 = portE + 1
PE3 = portE + 3
PE4 = portE + 4
PE5 = portE + 5
PE6 = portE + 6
PF0 = portF + 0
PF1 = portF + 1
PF2 = portF + 2
PF3 = portF + 3
PF4 = portF + 4
PF5 = portF + 5
PF6 = portF + 6
PF7 = portF + 7
PG0 = portG + 0
PG1 = portG + 1
PG2 = portG + 2
PG5 = portG + 5
PH0 = portH + 0
PH1 = portH + 1
PH3 = portH + 3
PH4 = portH + 4
PH5 = portH + 5
PH6 = portH + 6
PJ0 = portJ + 0
PJ1 = portJ + 1
PK0 = portK + 0
PK1 = portK + 1
PK2 = portK + 2
PK3 = portK + 3
PK4 = portH + 4
PK5 = portH + 5
PK6 = portH + 6
PK7 = portH + 7
PL0 = portL + 0
PL1 = portL + 1
PL2 = portL + 2
PL3 = portL + 3
PL4 = portL + 4
PL5 = portL + 5
PL6 = portL + 6
PL7 = portL + 7
)
// getPortMask returns the PORTx register and mask for the pin.
func (p Pin) getPortMask() (*volatile.Register8, uint8) {
switch {
case p >= PA0 && p <= PA7:
return avr.PORTA, 1 << uint8(p-portA)
case p >= PB0 && p <= PB7:
return avr.PORTB, 1 << uint8(p-portB)
case p >= PC0 && p <= PC7:
return avr.PORTC, 1 << uint8(p-portC)
case p >= PD0 && p <= PD7:
return avr.PORTD, 1 << uint8(p-portD)
case p >= PE0 && p <= PE6:
return avr.PORTE, 1 << uint8(p-portE)
case p >= PF0 && p <= PF7:
return avr.PORTF, 1 << uint8(p-portF)
case p >= PG0 && p <= PG5:
return avr.PORTG, 1 << uint8(p-portG)
case p >= PH0 && p <= PH6:
return avr.PORTH, 1 << uint8(p-portH)
case p >= PJ0 && p <= PJ1:
return avr.PORTJ, 1 << uint8(p-portJ)
case p >= PK0 && p <= PK7:
return avr.PORTK, 1 << uint8(p-portK)
case p >= PL0 && p <= PL7:
return avr.PORTL, 1 << uint8(p-portL)
default:
return avr.PORTA, 255
}
}
// PWM is one PWM peripheral, which consists of a counter and two output
// channels (that can be connected to two fixed pins). You can set the frequency
// using SetPeriod, but only for all the channels in this PWM peripheral at
// once.
type PWM struct {
num uint8
}
var (
Timer0 = PWM{0} // 8 bit timer for PB7 and PG5
Timer1 = PWM{1} // 16 bit timer for PB5 and PB6
Timer2 = PWM{2} // 8 bit timer for PB4 and PH6
Timer3 = PWM{3} // 16 bit timer for PE3, PE4 and PE5
Timer4 = PWM{4} // 16 bit timer for PH3, PH4 and PH5
Timer5 = PWM{5} // 16 bit timer for PL3, PL4 and PL5
)
// Configure enables and configures this PWM.
//
// For the two 8 bit timers, there is only a limited number of periods
// available, namely the CPU frequency divided by 256 and again divided by 1, 8,
// 64, 256, or 1024. For a MCU running at 16MHz, this would be a period of 16µs,
// 128µs, 1024µs, 4096µs, or 16384µs.
func (pwm PWM) Configure(config PWMConfig) error {
switch pwm.num {
case 0, 2: // 8-bit timers (Timer/counter 0 and Timer/counter 2)
// Calculate the timer prescaler.
// While we could configure a flexible top, that would sacrifice one of
// the PWM output compare registers and thus a PWM channel. I've chosen
// to instead limit this timer to a fixed number of frequencies.
var prescaler uint8
switch config.Period {
case 0, (uint64(1e9) * 256 * 1) / uint64(CPUFrequency()):
prescaler = 1
case (uint64(1e9) * 256 * 8) / uint64(CPUFrequency()):
prescaler = 2
case (uint64(1e9) * 256 * 64) / uint64(CPUFrequency()):
prescaler = 3
case (uint64(1e9) * 256 * 256) / uint64(CPUFrequency()):
prescaler = 4
case (uint64(1e9) * 256 * 1024) / uint64(CPUFrequency()):
prescaler = 5
default:
return ErrPWMPeriodTooLong
}
if pwm.num == 0 {
avr.TCCR0B.Set(prescaler)
// Set the PWM mode to fast PWM (mode = 3).
avr.TCCR0A.Set(avr.TCCR0A_WGM00 | avr.TCCR0A_WGM01)
} else {
avr.TCCR2B.Set(prescaler)
// Set the PWM mode to fast PWM (mode = 3).
avr.TCCR2A.Set(avr.TCCR2A_WGM20 | avr.TCCR2A_WGM21)
}
case 1, 3, 4, 5:
// The top value is the number of PWM ticks a PWM period takes. It is
// initially picked assuming an unlimited counter top and no PWM
// prescaler.
var top uint64
if config.Period == 0 {
// Use a top appropriate for LEDs. Picking a relatively low period
// here (0xff) for consistency with the other timers.
top = 0xff
} else {
// The formula below calculates the following formula, optimized:
// top = period * (CPUFrequency() / 1e9)
// By dividing the CPU frequency first (an operation that is easily
// optimized away) the period has less chance of overflowing.
top = config.Period * (uint64(CPUFrequency()) / 1000000) / 1000
}
// The ideal PWM period may be larger than would fit in the PWM counter,
// which is 16 bits (see maxTop). Therefore, try to make the PWM clock
// speed lower with a prescaler to make the top value fit the maximum
// top value.
const maxTop = 0x10000
var prescalingTop uint8
switch {
case top <= maxTop:
prescalingTop = 3<<3 | 1 // no prescaling
case top/8 <= maxTop:
prescalingTop = 3<<3 | 2 // divide by 8
top /= 8
case top/64 <= maxTop:
prescalingTop = 3<<3 | 3 // divide by 64
top /= 64
case top/256 <= maxTop:
prescalingTop = 3<<3 | 4 // divide by 256
top /= 256
case top/1024 <= maxTop:
prescalingTop = 3<<3 | 5 // divide by 1024
top /= 1024
default:
return ErrPWMPeriodTooLong
}
// A top of 0x10000 is at 100% duty cycle. Subtract one because the
// counter counts from 0, not 1 (avoiding an off-by-one).
top -= 1
switch pwm.num {
case 1:
avr.TCCR1A.Set(avr.TCCR1A_WGM11)
avr.TCCR1B.Set(prescalingTop)
avr.ICR1H.Set(uint8(top >> 8))
avr.ICR1L.Set(uint8(top))
case 3:
avr.TCCR3A.Set(avr.TCCR3A_WGM31)
avr.TCCR3B.Set(prescalingTop)
avr.ICR3H.Set(uint8(top >> 8))
avr.ICR3L.Set(uint8(top))
case 4:
avr.TCCR4A.Set(avr.TCCR4A_WGM41)
avr.TCCR4B.Set(prescalingTop)
avr.ICR4H.Set(uint8(top >> 8))
avr.ICR4L.Set(uint8(top))
case 5:
avr.TCCR5A.Set(avr.TCCR5A_WGM51)
avr.TCCR5B.Set(prescalingTop)
avr.ICR5H.Set(uint8(top >> 8))
avr.ICR5L.Set(uint8(top))
}
}
return nil
}
// SetPeriod updates the period of this PWM peripheral.
// To set a particular frequency, use the following formula:
//
// period = 1e9 / frequency
//
// If you use a period of 0, a period that works well for LEDs will be picked.
//
// SetPeriod will not change the prescaler, but also won't change the current
// value in any of the channels. This means that you may need to update the
// value for the particular channel.
//
// Note that you cannot pick any arbitrary period after the PWM peripheral has
// been configured. If you want to switch between frequencies, pick the lowest
// frequency (longest period) once when calling Configure and adjust the
// frequency here as needed.
func (pwm PWM) SetPeriod(period uint64) error {
if pwm.num == 0 || pwm.num == 2 {
return ErrPWMPeriodTooLong // TODO better error message
}
// The top value is the number of PWM ticks a PWM period takes. It is
// initially picked assuming an unlimited counter top and no PWM
// prescaler.
var top uint64
if period == 0 {
// Use a top appropriate for LEDs. Picking a relatively low period
// here (0xff) for consistency with the other timers.
top = 0xff
} else {
// The formula below calculates the following formula, optimized:
// top = period * (CPUFrequency() / 1e9)
// By dividing the CPU frequency first (an operation that is easily
// optimized away) the period has less chance of overflowing.
top = period * (uint64(CPUFrequency()) / 1000000) / 1000
}
var prescaler uint8
switch pwm.num {
case 1:
prescaler = avr.TCCR1B.Get() & 0x7
case 3:
prescaler = avr.TCCR3B.Get() & 0x7
case 4:
prescaler = avr.TCCR4B.Get() & 0x7
case 5:
prescaler = avr.TCCR5B.Get() & 0x7
}
switch prescaler {
case 1:
top /= 1
case 2:
top /= 8
case 3:
top /= 64
case 4:
top /= 256
case 5:
top /= 1024
}
// A top of 0x10000 is at 100% duty cycle. Subtract one because the counter
// counts from 0, not 1 (avoiding an off-by-one).
top -= 1
if top > 0xffff {
return ErrPWMPeriodTooLong
}
switch pwm.num {
case 1:
// Warning: this change is not atomic!
avr.ICR1H.Set(uint8(top >> 8))
avr.ICR1L.Set(uint8(top))
// ... and because of that, set the counter back to zero to avoid most of
// the effects of this non-atomicity.
avr.TCNT1H.Set(0)
avr.TCNT1L.Set(0)
case 3:
// Warning: this change is not atomic!
avr.ICR3H.Set(uint8(top >> 8))
avr.ICR3L.Set(uint8(top))
// ... and because of that, set the counter back to zero to avoid most of
// the effects of this non-atomicity.
avr.TCNT3H.Set(0)
avr.TCNT3L.Set(0)
case 4:
// Warning: this change is not atomic!
avr.ICR4H.Set(uint8(top >> 8))
avr.ICR4L.Set(uint8(top))
// ... and because of that, set the counter back to zero to avoid most of
// the effects of this non-atomicity.
avr.TCNT4H.Set(0)
avr.TCNT4L.Set(0)
case 5:
// Warning: this change is not atomic!
avr.ICR5H.Set(uint8(top >> 8))
avr.ICR5L.Set(uint8(top))
// ... and because of that, set the counter back to zero to avoid most of
// the effects of this non-atomicity.
avr.TCNT5H.Set(0)
avr.TCNT5L.Set(0)
}
return nil
}
// Top returns the current counter top, for use in duty cycle calculation. It
// will only change with a call to Configure or SetPeriod, otherwise it is
// constant.
//
// The value returned here is hardware dependent. In general, it's best to treat
// it as an opaque value that can be divided by some number and passed to Set
// (see Set documentation for more information).
func (pwm PWM) Top() uint32 {
switch pwm.num {
case 1:
// Timer 1 has a configurable top value.
low := avr.ICR1L.Get()
high := avr.ICR1H.Get()
return uint32(high)<<8 | uint32(low) + 1
case 3:
// Timer 3 has a configurable top value.
low := avr.ICR3L.Get()
high := avr.ICR3H.Get()
return uint32(high)<<8 | uint32(low) + 1
case 4:
// Timer 4 has a configurable top value.
low := avr.ICR4L.Get()
high := avr.ICR4H.Get()
return uint32(high)<<8 | uint32(low) + 1
case 5:
// Timer 5 has a configurable top value.
low := avr.ICR5L.Get()
high := avr.ICR5H.Get()
return uint32(high)<<8 | uint32(low) + 1
}
// Other timers go from 0 to 0xff (0x100 or 256 in total).
return 256
}
// Counter returns the current counter value of the timer in this PWM
// peripheral. It may be useful for debugging.
func (pwm PWM) Counter() uint32 {
switch pwm.num {
case 0:
return uint32(avr.TCNT0.Get())
case 1:
mask := interrupt.Disable()
low := avr.TCNT1L.Get()
high := avr.TCNT1H.Get()
interrupt.Restore(mask)
return uint32(high)<<8 | uint32(low)
case 2:
return uint32(avr.TCNT2.Get())
case 3:
mask := interrupt.Disable()
low := avr.TCNT3L.Get()
high := avr.TCNT3H.Get()
interrupt.Restore(mask)
return uint32(high)<<8 | uint32(low)
case 4:
mask := interrupt.Disable()
low := avr.TCNT4L.Get()
high := avr.TCNT4H.Get()
interrupt.Restore(mask)
return uint32(high)<<8 | uint32(low)
case 5:
mask := interrupt.Disable()
low := avr.TCNT5L.Get()
high := avr.TCNT5H.Get()
interrupt.Restore(mask)
return uint32(high)<<8 | uint32(low)
}
// Unknown PWM.
return 0
}
// Period returns the used PWM period in nanoseconds. It might deviate slightly
// from the configured period due to rounding.
func (pwm PWM) Period() uint64 {
var prescaler uint8
switch pwm.num {
case 0:
prescaler = avr.TCCR0B.Get() & 0x7
case 1:
prescaler = avr.TCCR1B.Get() & 0x7
case 2:
prescaler = avr.TCCR2B.Get() & 0x7
case 3:
prescaler = avr.TCCR3B.Get() & 0x7
case 4:
prescaler = avr.TCCR4B.Get() & 0x7
case 5:
prescaler = avr.TCCR5B.Get() & 0x7
}
top := uint64(pwm.Top())
switch prescaler {
case 1: // prescaler 1
return 1 * top * 1000 / uint64(CPUFrequency()/1e6)
case 2: // prescaler 8
return 8 * top * 1000 / uint64(CPUFrequency()/1e6)
case 3: // prescaler 64
return 64 * top * 1000 / uint64(CPUFrequency()/1e6)
case 4: // prescaler 256
return 256 * top * 1000 / uint64(CPUFrequency()/1e6)
case 5: // prescaler 1024
return 1024 * top * 1000 / uint64(CPUFrequency()/1e6)
default: // unknown clock source
return 0
}
}
// Channel returns a PWM channel for the given pin.
func (pwm PWM) Channel(pin Pin) (uint8, error) {
pin.Configure(PinConfig{Mode: PinOutput})
pin.Low()
switch pwm.num {
case 0:
switch pin {
case PB7: // channel A
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1)
return 0, nil
case PG5: // channel B
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
return 1, nil
}
case 1:
switch pin {
case PB5: // channel A
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1)
return 0, nil
case PB6: // channel B
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1)
return 1, nil
}
case 2:
switch pin {
case PB4: // channel A
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
return 0, nil
case PH6: // channel B
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1)
return 1, nil
}
case 3:
switch pin {
case PE3: // channel A
avr.TCCR3A.SetBits(avr.TCCR3A_COM3A1)
return 0, nil
case PE4: //channel B
avr.TCCR3A.SetBits(avr.TCCR3A_COM3B1)
return 1, nil
case PE5: //channel C
avr.TCCR3A.SetBits(avr.TCCR3A_COM3C1)
return 2, nil
}
case 4:
switch pin {
case PH3: // channel A
avr.TCCR4A.SetBits(avr.TCCR4A_COM4A1)
return 0, nil
case PH4: //channel B
avr.TCCR4A.SetBits(avr.TCCR4A_COM4B1)
return 1, nil
case PH5: //channel C
avr.TCCR4A.SetBits(avr.TCCR4A_COM4C1)
return 2, nil
}
case 5:
switch pin {
case PL3: // channel A
avr.TCCR5A.SetBits(avr.TCCR5A_COM5A1)
return 0, nil
case PL4: //channel B
avr.TCCR5A.SetBits(avr.TCCR5A_COM5B1)
return 1, nil
case PL5: //channel C
avr.TCCR5A.SetBits(avr.TCCR5A_COM5C1)
return 2, nil
}
}
return 0, ErrInvalidOutputPin
}
// SetInverting sets whether to invert the output of this channel.
// Without inverting, a 25% duty cycle would mean the output is high for 25% of
// the time and low for the rest. Inverting flips the output as if a NOT gate
// was placed at the output, meaning that the output would be 25% low and 75%
// high with a duty cycle of 25%.
//
// Note: the invert state may not be applied on the AVR until the next call to
// ch.Set().
func (pwm PWM) SetInverting(channel uint8, inverting bool) {
switch pwm.num {
case 0:
switch channel {
case 0: // channel A, PB7
if inverting {
avr.PORTB.SetBits(1 << 7) // PB7 high
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A0)
} else {
avr.PORTB.ClearBits(1 << 7) // PB7 low
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A0)
}
case 1: // channel B, PG5
if inverting {
avr.PORTG.SetBits(1 << 5) // PG5 high
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B0)
} else {
avr.PORTG.ClearBits(1 << 5) // PG5 low
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B0)
}
}
case 1:
// Note: the COM1A0/COM1B0 bit is not set with the configuration below.
// It will be set the following call to Set(), however.
switch channel {
case 0: // channel A, PB5
if inverting {
avr.PORTB.SetBits(1 << 5) // PB5 high
} else {
avr.PORTB.ClearBits(1 << 5) // PB5 low
}
case 1: // channel B, PB6
if inverting {
avr.PORTB.SetBits(1 << 6) // PB6 high
} else {
avr.PORTB.ClearBits(1 << 6) // PB6 low
}
}
case 2:
switch channel {
case 0: // channel A, PB4
if inverting {
avr.PORTB.SetBits(1 << 4) // PB4 high
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A0)
} else {
avr.PORTB.ClearBits(1 << 4) // PB4 low
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A0)
}
case 1: // channel B, PH6
if inverting {
avr.PORTH.SetBits(1 << 6) // PH6 high
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B0)
} else {
avr.PORTH.ClearBits(1 << 6) // PH6 low
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B0)
}
}
case 3:
// Note: the COM3A0/COM3B0 bit is not set with the configuration below.
// It will be set the following call to Set(), however.
switch channel {
case 0: // channel A, PE3
if inverting {
avr.PORTE.SetBits(1 << 3) // PE3 high
} else {
avr.PORTE.ClearBits(1 << 3) // PE3 low
}
case 1: // channel B, PE4
if inverting {
avr.PORTE.SetBits(1 << 4) // PE4 high
} else {
avr.PORTE.ClearBits(1 << 4) // PE4 low
}
case 2: // channel C, PE5
if inverting {
avr.PORTE.SetBits(1 << 5) // PE4 high
} else {
avr.PORTE.ClearBits(1 << 5) // PE4 low
}
}
case 4:
// Note: the COM3A0/COM3B0 bit is not set with the configuration below.
// It will be set the following call to Set(), however.
switch channel {
case 0: // channel A, PH3
if inverting {
avr.PORTH.SetBits(1 << 3) // PH3 high
} else {
avr.PORTH.ClearBits(1 << 3) // PH3 low
}
case 1: // channel B, PH4
if inverting {
avr.PORTH.SetBits(1 << 4) // PH4 high
} else {
avr.PORTH.ClearBits(1 << 4) // PH4 low
}
case 2: // channel C, PH5
if inverting {
avr.PORTH.SetBits(1 << 5) // PH4 high
} else {
avr.PORTH.ClearBits(1 << 5) // PH4 low
}
}
case 5:
// Note: the COM3A0/COM3B0 bit is not set with the configuration below.
// It will be set the following call to Set(), however.
switch channel {
case 0: // channel A, PL3
if inverting {
avr.PORTL.SetBits(1 << 3) // PL3 high
} else {
avr.PORTL.ClearBits(1 << 3) // PL3 low
}
case 1: // channel B, PL4
if inverting {
avr.PORTL.SetBits(1 << 4) // PL4 high
} else {
avr.PORTL.ClearBits(1 << 4) // PL4 low
}
case 2: // channel C, PH5
if inverting {
avr.PORTL.SetBits(1 << 5) // PL4 high
} else {
avr.PORTL.ClearBits(1 << 5) // PL4 low
}
}
}
}
// Set updates the channel value. This is used to control the channel duty
// cycle, in other words the fraction of time the channel output is high (or low
// when inverted). For example, to set it to a 25% duty cycle, use:
//
// pwm.Set(channel, pwm.Top() / 4)
//
// pwm.Set(channel, 0) will set the output to low and pwm.Set(channel,
// pwm.Top()) will set the output to high, assuming the output isn't inverted.
func (pwm PWM) Set(channel uint8, value uint32) {
switch pwm.num {
case 0:
value := uint16(value)
switch channel {
case 0: // channel A
if value == 0 {
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0A1)
} else {
avr.OCR0A.Set(uint8(value - 1))
avr.TCCR0A.SetBits(avr.TCCR0A_COM0A1)
}
case 1: // channel B
if value == 0 {
avr.TCCR0A.ClearBits(avr.TCCR0A_COM0B1)
} else {
avr.OCR0B.Set(uint8(value) - 1)
avr.TCCR0A.SetBits(avr.TCCR0A_COM0B1)
}
}
case 1:
mask := interrupt.Disable()
switch channel {
case 0: // channel A, PB5
if value == 0 {
avr.TCCR1A.ClearBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0)
} else {
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
avr.OCR1AH.Set(uint8(value >> 8))
avr.OCR1AL.Set(uint8(value))
if avr.PORTB.HasBits(1 << 5) { // is PB1 high?
// Yes, set the inverting bit.
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1 | avr.TCCR1A_COM1A0)
} else {
// No, output is non-inverting.
avr.TCCR1A.SetBits(avr.TCCR1A_COM1A1)
}
}
case 1: // channel B, PB6
if value == 0 {
avr.TCCR1A.ClearBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0)
} else {
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
avr.OCR1BH.Set(uint8(value >> 8))
avr.OCR1BL.Set(uint8(value))
if avr.PORTB.HasBits(1 << 6) { // is PB6 high?
// Yes, set the inverting bit.
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1 | avr.TCCR1A_COM1B0)
} else {
// No, output is non-inverting.
avr.TCCR1A.SetBits(avr.TCCR1A_COM1B1)
}
}
}
interrupt.Restore(mask)
case 2:
value := uint16(value)
switch channel {
case 0: // channel A
if value == 0 {
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2A1)
} else {
avr.OCR2A.Set(uint8(value - 1))
avr.TCCR2A.SetBits(avr.TCCR2A_COM2A1)
}
case 1: // channel B
if value == 0 {
avr.TCCR2A.ClearBits(avr.TCCR2A_COM2B1)
} else {
avr.OCR2B.Set(uint8(value - 1))
avr.TCCR2A.SetBits(avr.TCCR2A_COM2B1)
}
}
case 3:
mask := interrupt.Disable()
switch channel {
case 0: // channel A, PE3
if value == 0 {
avr.TCCR3A.ClearBits(avr.TCCR3A_COM3A1 | avr.TCCR3A_COM3A0)
} else {
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
avr.OCR3AH.Set(uint8(value >> 8))
avr.OCR3AL.Set(uint8(value))
if avr.PORTE.HasBits(1 << 3) { // is PE3 high?
// Yes, set the inverting bit.
avr.TCCR3A.SetBits(avr.TCCR3A_COM3A1 | avr.TCCR3A_COM3A0)
} else {
// No, output is non-inverting.
avr.TCCR3A.SetBits(avr.TCCR3A_COM3A1)
}
}
case 1: // channel B, PE4
if value == 0 {
avr.TCCR3A.ClearBits(avr.TCCR3A_COM3B1 | avr.TCCR3A_COM3B0)
} else {
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
avr.OCR3BH.Set(uint8(value >> 8))
avr.OCR3BL.Set(uint8(value))
if avr.PORTE.HasBits(1 << 4) { // is PE4 high?
// Yes, set the inverting bit.
avr.TCCR3A.SetBits(avr.TCCR3A_COM3B1 | avr.TCCR3A_COM3B0)
} else {
// No, output is non-inverting.
avr.TCCR3A.SetBits(avr.TCCR3A_COM3B1)
}
}
case 2: // channel C, PE5
if value == 0 {
avr.TCCR3A.ClearBits(avr.TCCR3A_COM3C1 | avr.TCCR3A_COM3C0)
} else {
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
avr.OCR3CH.Set(uint8(value >> 8))
avr.OCR3CL.Set(uint8(value))
if avr.PORTE.HasBits(1 << 5) { // is PE5 high?
// Yes, set the inverting bit.
avr.TCCR3A.SetBits(avr.TCCR3A_COM3C1 | avr.TCCR3A_COM3C0)
} else {
// No, output is non-inverting.
avr.TCCR3A.SetBits(avr.TCCR3A_COM3C1)
}
}
}
interrupt.Restore(mask)
case 4:
mask := interrupt.Disable()
switch channel {
case 0: // channel A, PH3
if value == 0 {
avr.TCCR4A.ClearBits(avr.TCCR4A_COM4A1 | avr.TCCR4A_COM4A0)
} else {
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
avr.OCR4AH.Set(uint8(value >> 8))
avr.OCR4AL.Set(uint8(value))
if avr.PORTH.HasBits(1 << 3) { // is PH3 high?
// Yes, set the inverting bit.
avr.TCCR4A.SetBits(avr.TCCR4A_COM4A1 | avr.TCCR4A_COM4A0)
} else {
// No, output is non-inverting.
avr.TCCR4A.SetBits(avr.TCCR4A_COM4A1)
}
}
case 1: // channel B, PH4
if value == 0 {
avr.TCCR4A.ClearBits(avr.TCCR4A_COM4B1 | avr.TCCR4A_COM4B0)
} else {
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
avr.OCR4BH.Set(uint8(value >> 8))
avr.OCR4BL.Set(uint8(value))
if avr.PORTH.HasBits(1 << 4) { // is PH4 high?
// Yes, set the inverting bit.
avr.TCCR4A.SetBits(avr.TCCR4A_COM4B1 | avr.TCCR4A_COM4B0)
} else {
// No, output is non-inverting.
avr.TCCR4A.SetBits(avr.TCCR4A_COM4B1)
}
}
case 2: // channel C, PH5
if value == 0 {
avr.TCCR4A.ClearBits(avr.TCCR4A_COM4C1 | avr.TCCR4A_COM4C0)
} else {
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
avr.OCR4CH.Set(uint8(value >> 8))
avr.OCR4CL.Set(uint8(value))
if avr.PORTH.HasBits(1 << 5) { // is PH5 high?
// Yes, set the inverting bit.
avr.TCCR4A.SetBits(avr.TCCR4A_COM4C1 | avr.TCCR4A_COM4C0)
} else {
// No, output is non-inverting.
avr.TCCR4A.SetBits(avr.TCCR4A_COM4C1)
}
}
}
interrupt.Restore(mask)
case 5:
mask := interrupt.Disable()
switch channel {
case 0: // channel A, PL3
if value == 0 {
avr.TCCR5A.ClearBits(avr.TCCR5A_COM5A1 | avr.TCCR5A_COM5A0)
} else {
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
avr.OCR5AH.Set(uint8(value >> 8))
avr.OCR5AL.Set(uint8(value))
if avr.PORTL.HasBits(1 << 3) { // is PL3 high?
// Yes, set the inverting bit.
avr.TCCR5A.SetBits(avr.TCCR5A_COM5A1 | avr.TCCR5A_COM5A0)
} else {
// No, output is non-inverting.
avr.TCCR5A.SetBits(avr.TCCR5A_COM5A1)
}
}
case 1: // channel B, PL4
if value == 0 {
avr.TCCR5A.ClearBits(avr.TCCR5A_COM5B1 | avr.TCCR5A_COM5B0)
} else {
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
avr.OCR5BH.Set(uint8(value >> 8))
avr.OCR5BL.Set(uint8(value))
if avr.PORTL.HasBits(1 << 4) { // is PL4 high?
// Yes, set the inverting bit.
avr.TCCR5A.SetBits(avr.TCCR5A_COM5B1 | avr.TCCR5A_COM5B0)
} else {
// No, output is non-inverting.
avr.TCCR5A.SetBits(avr.TCCR5A_COM5B1)
}
}
case 2: // channel C, PL5
if value == 0 {
avr.TCCR5A.ClearBits(avr.TCCR5A_COM5C1 | avr.TCCR5A_COM5C0)
} else {
value := uint16(value) - 1 // yes, this is safe (it relies on underflow)
avr.OCR5CH.Set(uint8(value >> 8))
avr.OCR5CL.Set(uint8(value))
if avr.PORTL.HasBits(1 << 5) { // is PL5 high?
// Yes, set the inverting bit.
avr.TCCR5A.SetBits(avr.TCCR5A_COM5C1 | avr.TCCR5A_COM5C0)
} else {
// No, output is non-inverting.
avr.TCCR5A.SetBits(avr.TCCR5A_COM5C1)
}
}
}
interrupt.Restore(mask)
}
}
// SPI configuration
var SPI0 = SPI{
spcr: avr.SPCR,
spdr: avr.SPDR,
spsr: avr.SPSR,
sck: PB1,
sdo: PB2,
sdi: PB3,
cs: PB0}
+9 -18
View File
@@ -2298,7 +2298,7 @@ func handleStandardSetup(setup usbSetup) bool {
func cdcSetup(setup usbSetup) bool {
if setup.bmRequestType == usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE {
if setup.bRequest == usb_CDC_GET_LINE_CODING {
var b [cdcLineInfoSize]byte
b := make([]byte, 7)
b[0] = byte(usbLineInfo.dwDTERate)
b[1] = byte(usbLineInfo.dwDTERate >> 8)
b[2] = byte(usbLineInfo.dwDTERate >> 16)
@@ -2307,18 +2307,14 @@ func cdcSetup(setup usbSetup) bool {
b[5] = byte(usbLineInfo.bParityType)
b[6] = byte(usbLineInfo.bDataBits)
sendUSBPacket(0, b[:])
sendUSBPacket(0, b)
return true
}
}
if setup.bmRequestType == usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE {
if setup.bRequest == usb_CDC_SET_LINE_CODING {
b, err := receiveUSBControlPacket()
if err != nil {
return false
}
b := receiveUSBControlPacket()
usbLineInfo.dwDTERate = uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
usbLineInfo.bCharFormat = b[4]
usbLineInfo.bParityType = b[5]
@@ -2365,9 +2361,7 @@ func sendUSBPacket(ep uint32, data []byte) {
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(uint32((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos))
}
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
var b [cdcLineInfoSize]byte
func receiveUSBControlPacket() []byte {
// address
usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0]))))
@@ -2382,7 +2376,7 @@ func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
for (getEPSTATUS(0) & sam.USB_DEVICE_EPSTATUS_BK0RDY) == 0 {
timeout--
if timeout == 0 {
return b, errUSBCDCReadTimeout
return []byte{}
}
}
@@ -2391,7 +2385,7 @@ func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
for (getEPINTFLAG(0) & sam.USB_DEVICE_EPINTFLAG_TRCPT0) == 0 {
timeout--
if timeout == 0 {
return b, errUSBCDCReadTimeout
return []byte{}
}
}
@@ -2399,13 +2393,10 @@ func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
bytesread := uint32((usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.Get() >>
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
if bytesread != cdcLineInfoSize {
return b, errUSBCDCBytesRead
}
data := make([]byte, bytesread)
copy(data, udd_ep_out_cache_buffer[0][:])
copy(b[:7], udd_ep_out_cache_buffer[0][:7])
return b, nil
return data
}
func handleEndpoint(ep uint32) {
+9 -18
View File
@@ -2426,7 +2426,7 @@ func handleStandardSetup(setup usbSetup) bool {
func cdcSetup(setup usbSetup) bool {
if setup.bmRequestType == usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE {
if setup.bRequest == usb_CDC_GET_LINE_CODING {
var b [cdcLineInfoSize]byte
b := make([]byte, 7)
b[0] = byte(usbLineInfo.dwDTERate)
b[1] = byte(usbLineInfo.dwDTERate >> 8)
b[2] = byte(usbLineInfo.dwDTERate >> 16)
@@ -2435,18 +2435,14 @@ func cdcSetup(setup usbSetup) bool {
b[5] = byte(usbLineInfo.bParityType)
b[6] = byte(usbLineInfo.bDataBits)
sendUSBPacket(0, b[:])
sendUSBPacket(0, b)
return true
}
}
if setup.bmRequestType == usb_REQUEST_HOSTTODEVICE_CLASS_INTERFACE {
if setup.bRequest == usb_CDC_SET_LINE_CODING {
b, err := receiveUSBControlPacket()
if err != nil {
return false
}
b := receiveUSBControlPacket()
usbLineInfo.dwDTERate = uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
usbLineInfo.bCharFormat = b[4]
usbLineInfo.bParityType = b[5]
@@ -2493,9 +2489,7 @@ func sendUSBPacket(ep uint32, data []byte) {
usbEndpointDescriptors[ep].DeviceDescBank[1].PCKSIZE.SetBits(uint32((len(data) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask) << usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos))
}
func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
var b [cdcLineInfoSize]byte
func receiveUSBControlPacket() []byte {
// address
usbEndpointDescriptors[0].DeviceDescBank[0].ADDR.Set(uint32(uintptr(unsafe.Pointer(&udd_ep_out_cache_buffer[0]))))
@@ -2510,7 +2504,7 @@ func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
for (getEPSTATUS(0) & sam.USB_DEVICE_ENDPOINT_EPSTATUS_BK0RDY) == 0 {
timeout--
if timeout == 0 {
return b, errUSBCDCReadTimeout
return []byte{}
}
}
@@ -2519,7 +2513,7 @@ func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
for (getEPINTFLAG(0) & sam.USB_DEVICE_ENDPOINT_EPINTFLAG_TRCPT1) == 0 {
timeout--
if timeout == 0 {
return b, errUSBCDCReadTimeout
return []byte{}
}
}
@@ -2527,13 +2521,10 @@ func receiveUSBControlPacket() ([cdcLineInfoSize]byte, error) {
bytesread := uint32((usbEndpointDescriptors[0].DeviceDescBank[0].PCKSIZE.Get() >>
usb_DEVICE_PCKSIZE_BYTE_COUNT_Pos) & usb_DEVICE_PCKSIZE_BYTE_COUNT_Mask)
if bytesread != cdcLineInfoSize {
return b, errUSBCDCBytesRead
}
data := make([]byte, bytesread)
copy(data, udd_ep_out_cache_buffer[0][:])
copy(b[:7], udd_ep_out_cache_buffer[0][:7])
return b, nil
return data
}
func handleEndpoint(ep uint32) {
+51 -40
View File
@@ -11,49 +11,60 @@ import "device/sam"
const HSRAM_SIZE = 0x00040000
// This chip has five TCC peripherals, which have PWM as one feature.
var (
TCC0 = (*TCC)(sam.TCC0)
TCC1 = (*TCC)(sam.TCC1)
TCC2 = (*TCC)(sam.TCC2)
TCC3 = (*TCC)(sam.TCC3)
TCC4 = (*TCC)(sam.TCC4)
)
// InitPWM initializes the PWM interface.
func InitPWM() {
// turn on timer clocks used for PWM
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_ | sam.MCLK_APBBMASK_TCC1_)
sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_ | sam.MCLK_APBCMASK_TCC3_)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_TCC4_)
func (tcc *TCC) configureClock() {
// Turn on timer clocks used for TCC and use generic clock generator 0.
switch tcc.timer() {
case sam.TCC0:
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC1:
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC2:
sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC2].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC3:
sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC3].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC4:
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_TCC4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
}
//use clock generator 0
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC2].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
func (tcc *TCC) timerNum() uint8 {
switch tcc.timer() {
case sam.TCC0:
return 0
case sam.TCC1:
return 1
case sam.TCC2:
return 2
case sam.TCC3:
return 3
case sam.TCC4:
return 4
// getTimer returns the timer to be used for PWM on this pin
func (pwm PWM) getTimer() *sam.TCC_Type {
switch pwm.Pin {
case PC18:
return sam.TCC0
case PC19:
return sam.TCC0
case PC20:
return sam.TCC0
case PC21:
return sam.TCC0
case PD20:
return sam.TCC1
case PD21:
return sam.TCC1
case PB18:
return sam.TCC1
case PB12:
return sam.TCC3
case PB13:
return sam.TCC3
case PA15:
return sam.TCC2
case PC17:
return sam.TCC0
case PC16:
return sam.TCC0
case PA14:
return sam.TCC2
case PB15:
return sam.TCC4
case PB14:
return sam.TCC4
case PB20:
return sam.TCC1
case PB21:
return sam.TCC1
default:
return 0x0f // should not happen
return nil // not supported on this pin
}
}
-59
View File
@@ -1,59 +0,0 @@
// +build sam,atsame51,atsame51j19
// Peripheral abstraction layer for the atsame51.
//
// Datasheet:
// http://ww1.microchip.com/downloads/en/DeviceDoc/SAM_D5xE5x_Family_Data_Sheet_DS60001507F.pdf
//
package machine
import "device/sam"
const HSRAM_SIZE = 0x00030000
// This chip has five TCC peripherals, which have PWM as one feature.
var (
TCC0 = (*TCC)(sam.TCC0)
TCC1 = (*TCC)(sam.TCC1)
TCC2 = (*TCC)(sam.TCC2)
TCC3 = (*TCC)(sam.TCC3)
TCC4 = (*TCC)(sam.TCC4)
)
func (tcc *TCC) configureClock() {
// Turn on timer clocks used for the TCC and use generic clock generator 0.
switch tcc.timer() {
case sam.TCC0:
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC1:
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC2:
sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC2].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC3:
sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC3].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC4:
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_TCC4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
}
}
func (tcc *TCC) timerNum() uint8 {
switch tcc.timer() {
case sam.TCC0:
return 0
case sam.TCC1:
return 1
case sam.TCC2:
return 2
case sam.TCC3:
return 3
case sam.TCC4:
return 4
default:
return 0x0f // should not happen
}
}
-59
View File
@@ -1,59 +0,0 @@
// +build sam,atsame5x,atsame54p20
// Peripheral abstraction layer for the atsame54.
//
// Datasheet:
// http://ww1.microchip.com/downloads/en/DeviceDoc/60001507C.pdf
//
package machine
import "device/sam"
const HSRAM_SIZE = 0x00040000
// This chip has five TCC peripherals, which have PWM as one feature.
var (
TCC0 = (*TCC)(sam.TCC0)
TCC1 = (*TCC)(sam.TCC1)
TCC2 = (*TCC)(sam.TCC2)
TCC3 = (*TCC)(sam.TCC3)
TCC4 = (*TCC)(sam.TCC4)
)
func (tcc *TCC) configureClock() {
// Turn on timer clocks used for TCC and use generic clock generator 0.
switch tcc.timer() {
case sam.TCC0:
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC1:
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_TCC1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC2:
sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC2].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC3:
sam.MCLK.APBCMASK.SetBits(sam.MCLK_APBCMASK_TCC3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC3].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
case sam.TCC4:
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_TCC4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_TCC4].Set((sam.GCLK_PCHCTRL_GEN_GCLK0 << sam.GCLK_PCHCTRL_GEN_Pos) | sam.GCLK_PCHCTRL_CHEN)
}
}
func (tcc *TCC) timerNum() uint8 {
switch tcc.timer() {
case sam.TCC0:
return 0
case sam.TCC1:
return 1
case sam.TCC2:
return 2
case sam.TCC3:
return 3
case sam.TCC4:
return 4
default:
return 0x0f // should not happen
}
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -54,7 +54,7 @@ func (d FramebufDisplay) Size() (x, y int16) {
}
func (d FramebufDisplay) SetPixel(x, y int16, c color.RGBA) {
d.port[y][x].Set((uint16(c.R) >> 3) | ((uint16(c.G) >> 3) << 5) | ((uint16(c.B) >> 3) << 10))
d.port[y][x].Set(uint16(c.R)&0x1f | uint16(c.G)&0x1f<<5 | uint16(c.B)&0x1f<<10)
}
func (d FramebufDisplay) Display() error {
+3 -4
View File
@@ -83,8 +83,7 @@ func (i2c *I2C) setPins(scl, sda Pin) {
// PWM
var (
PWM0 = &PWM{PWM: nrf.PWM0}
PWM1 = &PWM{PWM: nrf.PWM1}
PWM2 = &PWM{PWM: nrf.PWM2}
PWM3 = &PWM{PWM: nrf.PWM3}
pwmChannelPins = [4]uint32{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF}
pwms = [4]*nrf.PWM_Type{nrf.PWM0, nrf.PWM1, nrf.PWM2, nrf.PWM3}
pwmChannelSequence [4]uint16
)
+2 -2
View File
@@ -445,7 +445,7 @@ func handleStandardSetup(setup usbSetup) bool {
func cdcSetup(setup usbSetup) bool {
if setup.bmRequestType == usb_REQUEST_DEVICETOHOST_CLASS_INTERFACE {
if setup.bRequest == usb_CDC_GET_LINE_CODING {
var b [cdcLineInfoSize]byte
b := make([]byte, 7)
b[0] = byte(usbLineInfo.dwDTERate)
b[1] = byte(usbLineInfo.dwDTERate >> 8)
b[2] = byte(usbLineInfo.dwDTERate >> 16)
@@ -454,7 +454,7 @@ func cdcSetup(setup usbSetup) bool {
b[5] = byte(usbLineInfo.bParityType)
b[6] = byte(usbLineInfo.bDataBits)
sendUSBPacket(0, b[:])
sendUSBPacket(0, b)
return true
}
}
+4 -6
View File
@@ -55,11 +55,9 @@ const (
gpioPullMask = 0x3
// OSPEED bitfields.
gpioOutputSpeedVeryHigh = 3
gpioOutputSpeedHigh = 2
gpioOutputSpeedMedium = 1
gpioOutputSpeedLow = 0
gpioOutputSpeedMask = 0x3
gpioOutputSpeedHigh = 2
gpioOutputSpeedLow = 0
gpioOutputSpeedMask = 0x3
)
// Configure this pin with the given configuration
@@ -122,7 +120,7 @@ func (p Pin) ConfigureAltFunc(config PinConfig, altFunc uint8) {
// SPI
case PinModeSPICLK:
port.MODER.ReplaceBits(gpioModeAlternate, gpioModeMask, pos)
port.OSPEEDR.ReplaceBits(gpioOutputSpeedHigh, gpioOutputSpeedMask, pos)
port.OSPEEDR.ReplaceBits(gpioOutputSpeedLow, gpioOutputSpeedMask, pos)
port.PUPDR.ReplaceBits(gpioPullFloating, gpioPullMask, pos)
p.SetAltFunc(altFunc)
case PinModeSPISDO:
+4 -12
View File
@@ -1,4 +1,4 @@
// +build stm32,!stm32f7x2,!stm32l5x2
// +build stm32,!stm32f7x2,!stm32l5x2,!stm32l4x2
package machine
@@ -6,7 +6,6 @@ package machine
import (
"device/stm32"
"runtime/volatile"
"unsafe"
)
@@ -87,12 +86,7 @@ func (spi SPI) Configure(config SPIConfig) {
// now set the configuration
spi.Bus.CR1.Set(conf)
// Series-specific configuration to set 8-bit transfer mode
spi.config8Bits()
// enable SPI
spi.Bus.CR1.SetBits(stm32.SPI_CR1_SPE)
spi.Bus.CR2.SetBits((conf & stm32.SPI_CR1_SSM_Msk) >> 16)
}
// Transfer writes/reads a single byte using the SPI interface.
@@ -109,10 +103,8 @@ func (spi SPI) Transfer(w byte) (byte, error) {
// 5. Wait until TXE=1 and then wait until BSY=0 before disabling the SPI.
// put output word (8-bit) in data register (DR), which is parallel-loaded
// into shift register, and shifted out on MOSI. Some series have 16-bit
// register but writes must be strictly 8-bit to output a byte. Writing
// 16-bits indicates a packed transfer (2 bytes).
(*volatile.Register8)(unsafe.Pointer(&spi.Bus.DR.Reg)).Set(w)
// into shift register, and shifted out on MOSI.
spi.Bus.DR.Set(uint32(w))
// wait for SPI bus receive buffer not empty bit (RXNE) to be set.
// warning: blocks forever until this condition is met.
-4
View File
@@ -161,10 +161,6 @@ var (
SPI0 = SPI1
)
func (spi SPI) config8Bits() {
// no-op on this series
}
// Set baud rate for SPI
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
var conf uint32
-4
View File
@@ -67,10 +67,6 @@ type SPI struct {
AltFuncSelector uint8
}
func (spi SPI) config8Bits() {
// no-op on this series
}
func (spi SPI) configurePins(config SPIConfig) {
config.SCK.ConfigureAltFunc(PinConfig{Mode: PinModeSPICLK}, spi.AltFuncSelector)
config.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector)
-4
View File
@@ -70,10 +70,6 @@ type SPI struct {
AltFuncSelector uint8
}
func (spi SPI) config8Bits() {
// no-op on this series
}
// Set baud rate for SPI
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
var conf uint32
-4
View File
@@ -184,10 +184,6 @@ type SPI struct {
AltFuncSelector uint8
}
func (spi SPI) config8Bits() {
// no-op on this series
}
// Set baud rate for SPI
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
var conf uint32
-64
View File
@@ -182,67 +182,3 @@ func enableAltFuncClock(bus unsafe.Pointer) {
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM1EN)
}
}
//---------- SPI related types and code
// SPI on the STM32Fxxx using MODER / alternate function pins
type SPI struct {
Bus *stm32.SPI_Type
AltFuncSelector uint8
}
func (spi SPI) config8Bits() {
// Set rx threshold to 8-bits, so RXNE flag is set for 1 byte
// (common STM32 SPI implementation does 8-bit transfers only)
spi.Bus.CR2.SetBits(stm32.SPI_CR2_FRXTH)
}
// Set baud rate for SPI
func (spi SPI) getBaudRate(config SPIConfig) uint32 {
var conf uint32
// Default
if config.Frequency == 0 {
config.Frequency = 4e6
}
localFrequency := config.Frequency
// set frequency dependent on PCLK prescaler. Since these are rather weird
// speeds due to the CPU freqency, pick a range up to that frquency for
// clients to use more human-understandable numbers, e.g. nearest 100KHz
// These are based on 80MHz peripheral clock frquency
switch {
case localFrequency < 312500:
conf = stm32.SPI_CR1_BR_Div256
case localFrequency < 625000:
conf = stm32.SPI_CR1_BR_Div128
case localFrequency < 1250000:
conf = stm32.SPI_CR1_BR_Div64
case localFrequency < 2500000:
conf = stm32.SPI_CR1_BR_Div32
case localFrequency < 5000000:
conf = stm32.SPI_CR1_BR_Div16
case localFrequency < 10000000:
conf = stm32.SPI_CR1_BR_Div8
// NOTE: many SPI components won't operate reliably (or at all) above 10MHz
// Check the datasheet of the part
case localFrequency < 20000000:
conf = stm32.SPI_CR1_BR_Div4
case localFrequency < 40000000:
conf = stm32.SPI_CR1_BR_Div2
default:
// None of the specific baudrates were selected; choose the lowest speed
conf = stm32.SPI_CR1_BR_Div256
}
return conf << stm32.SPI_CR1_BR_Pos
}
// Configure SPI pins for input output and clock
func (spi SPI) configurePins(config SPIConfig) {
config.SCK.ConfigureAltFunc(PinConfig{Mode: PinModeSPICLK}, spi.AltFuncSelector)
config.SDO.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDO}, spi.AltFuncSelector)
config.SDI.ConfigureAltFunc(PinConfig{Mode: PinModeSPISDI}, spi.AltFuncSelector)
}
+1 -1
View File
@@ -1,4 +1,4 @@
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2 fe310 k210 atmega
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2,!stm32l4x2 fe310 k210 atmega
package machine
+35 -75
View File
@@ -12,8 +12,6 @@ const deviceDescriptorSize = 18
var (
errUSBCDCBufferEmpty = errors.New("USB-CDC buffer empty")
errUSBCDCWriteByteTimeout = errors.New("USB-CDC write byte timeout")
errUSBCDCReadTimeout = errors.New("USB-CDC read timeout")
errUSBCDCBytesRead = errors.New("USB-CDC invalid number of bytes read")
)
// DeviceDescriptor implements the USB standard device descriptor.
@@ -45,8 +43,8 @@ func NewDeviceDescriptor(class, subClass, proto, packetSize0 uint8, vid, pid, ve
}
// Bytes returns DeviceDescriptor data
func (d DeviceDescriptor) Bytes() [deviceDescriptorSize]byte {
var b [deviceDescriptorSize]byte
func (d DeviceDescriptor) Bytes() []byte {
b := make([]byte, deviceDescriptorSize)
b[0] = byte(d.bLength)
b[1] = byte(d.bDescriptorType)
b[2] = byte(d.bcdUSB)
@@ -93,8 +91,8 @@ func NewConfigDescriptor(totalLength uint16, interfaces uint8) ConfigDescriptor
}
// Bytes returns ConfigDescriptor data.
func (d ConfigDescriptor) Bytes() [configDescriptorSize]byte {
var b [configDescriptorSize]byte
func (d ConfigDescriptor) Bytes() []byte {
b := make([]byte, configDescriptorSize)
b[0] = byte(d.bLength)
b[1] = byte(d.bDescriptorType)
b[2] = byte(d.wTotalLength)
@@ -133,8 +131,8 @@ func NewInterfaceDescriptor(n, numEndpoints, class, subClass, protocol uint8) In
}
// Bytes returns InterfaceDescriptor data.
func (d InterfaceDescriptor) Bytes() [interfaceDescriptorSize]byte {
var b [interfaceDescriptorSize]byte
func (d InterfaceDescriptor) Bytes() []byte {
b := make([]byte, interfaceDescriptorSize)
b[0] = byte(d.bLength)
b[1] = byte(d.bDescriptorType)
b[2] = byte(d.bInterfaceNumber)
@@ -169,8 +167,8 @@ func NewEndpointDescriptor(addr, attr uint8, packetSize uint16, interval uint8)
}
// Bytes returns EndpointDescriptor data.
func (d EndpointDescriptor) Bytes() [endpointDescriptorSize]byte {
var b [endpointDescriptorSize]byte
func (d EndpointDescriptor) Bytes() []byte {
b := make([]byte, endpointDescriptorSize)
b[0] = byte(d.bLength)
b[1] = byte(d.bDescriptorType)
b[2] = byte(d.bEndpointAddress)
@@ -207,8 +205,8 @@ func NewIADDescriptor(firstInterface, count, class, subClass, protocol uint8) IA
}
// Bytes returns IADDescriptor data.
func (d IADDescriptor) Bytes() [iadDescriptorSize]byte {
var b [iadDescriptorSize]byte
func (d IADDescriptor) Bytes() []byte {
b := make([]byte, iadDescriptorSize)
b[0] = byte(d.bLength)
b[1] = byte(d.bDescriptorType)
b[2] = byte(d.bFirstInterface)
@@ -237,8 +235,8 @@ func NewCDCCSInterfaceDescriptor(subtype, d0, d1 uint8) CDCCSInterfaceDescriptor
}
// Bytes returns CDCCSInterfaceDescriptor data.
func (d CDCCSInterfaceDescriptor) Bytes() [cdcCSInterfaceDescriptorSize]byte {
var b [cdcCSInterfaceDescriptorSize]byte
func (d CDCCSInterfaceDescriptor) Bytes() []byte {
b := make([]byte, cdcCSInterfaceDescriptorSize)
b[0] = byte(d.len)
b[1] = byte(d.dtype)
b[2] = byte(d.subtype)
@@ -264,8 +262,8 @@ func NewCMFunctionalDescriptor(subtype, d0, d1 uint8) CMFunctionalDescriptor {
}
// Bytes returns the CMFunctionalDescriptor data.
func (d CMFunctionalDescriptor) Bytes() [cmFunctionalDescriptorSize]byte {
var b [cmFunctionalDescriptorSize]byte
func (d CMFunctionalDescriptor) Bytes() []byte {
b := make([]byte, cmFunctionalDescriptorSize)
b[0] = byte(d.bFunctionLength)
b[1] = byte(d.bDescriptorType)
b[2] = byte(d.bDescriptorSubtype)
@@ -290,8 +288,8 @@ func NewACMFunctionalDescriptor(subtype, d0 uint8) ACMFunctionalDescriptor {
}
// Bytes returns the ACMFunctionalDescriptor data.
func (d ACMFunctionalDescriptor) Bytes() [acmFunctionalDescriptorSize]byte {
var b [acmFunctionalDescriptorSize]byte
func (d ACMFunctionalDescriptor) Bytes() []byte {
b := make([]byte, acmFunctionalDescriptorSize)
b[0] = byte(d.len)
b[1] = byte(d.dtype)
b[2] = byte(d.subtype)
@@ -353,51 +351,19 @@ const cdcSize = iadDescriptorSize +
endpointDescriptorSize
// Bytes returns CDCDescriptor data.
func (d CDCDescriptor) Bytes() [cdcSize]byte {
var b [cdcSize]byte
offset := 0
iad := d.iad.Bytes()
copy(b[offset:], iad[:])
offset += len(iad)
cif := d.cif.Bytes()
copy(b[offset:], cif[:])
offset += len(cif)
header := d.header.Bytes()
copy(b[offset:], header[:])
offset += len(header)
controlManagement := d.controlManagement.Bytes()
copy(b[offset:], controlManagement[:])
offset += len(controlManagement)
functionalDescriptor := d.functionalDescriptor.Bytes()
copy(b[offset:], functionalDescriptor[:])
offset += len(functionalDescriptor)
callManagement := d.callManagement.Bytes()
copy(b[offset:], callManagement[:])
offset += len(callManagement)
cifin := d.cifin.Bytes()
copy(b[offset:], cifin[:])
offset += len(cifin)
dif := d.dif.Bytes()
copy(b[offset:], dif[:])
offset += len(dif)
out := d.out.Bytes()
copy(b[offset:], out[:])
offset += len(out)
in := d.in.Bytes()
copy(b[offset:], in[:])
offset += len(in)
return b
func (d CDCDescriptor) Bytes() []byte {
var buf []byte
buf = append(buf, d.iad.Bytes()...)
buf = append(buf, d.cif.Bytes()...)
buf = append(buf, d.header.Bytes()...)
buf = append(buf, d.controlManagement.Bytes()...)
buf = append(buf, d.functionalDescriptor.Bytes()...)
buf = append(buf, d.callManagement.Bytes()...)
buf = append(buf, d.cifin.Bytes()...)
buf = append(buf, d.dif.Bytes()...)
buf = append(buf, d.out.Bytes()...)
buf = append(buf, d.in.Bytes()...)
return buf
}
// MSCDescriptor is not used yet.
@@ -407,8 +373,6 @@ type MSCDescriptor struct {
out EndpointDescriptor
}
const cdcLineInfoSize = 7
type cdcLineInfo struct {
dwDTERate uint32
bCharFormat uint8
@@ -669,8 +633,7 @@ func sendDescriptor(setup usbSetup) {
if setup.wLength < deviceDescriptorSize {
l = int(setup.wLength)
}
buf := dd.Bytes()
sendUSBPacket(0, buf[:l])
sendUSBPacket(0, dd.Bytes()[:l])
return
case usb_STRING_DESCRIPTOR_TYPE:
@@ -706,8 +669,7 @@ func sendConfiguration(setup usbSetup) {
if setup.wLength == 9 {
sz := uint16(configDescriptorSize + cdcSize)
config := NewConfigDescriptor(sz, 2)
configBuf := config.Bytes()
sendUSBPacket(0, configBuf[:])
sendUSBPacket(0, config.Bytes())
} else {
iad := NewIADDescriptor(0, 2, usb_CDC_COMMUNICATION_INTERFACE_CLASS, usb_CDC_ABSTRACT_CONTROL_MODEL, 0)
@@ -743,12 +705,10 @@ func sendConfiguration(setup usbSetup) {
sz := uint16(configDescriptorSize + cdcSize)
config := NewConfigDescriptor(sz, 2)
configBuf := config.Bytes()
cdcBuf := cdc.Bytes()
var buf [configDescriptorSize + cdcSize]byte
copy(buf[0:], configBuf[:])
copy(buf[configDescriptorSize:], cdcBuf[:])
buf := make([]byte, 0, sz)
buf = append(buf, config.Bytes()...)
buf = append(buf, cdc.Bytes()...)
sendUSBPacket(0, buf[:])
sendUSBPacket(0, buf)
}
}
-3
View File
@@ -322,9 +322,6 @@ func TypeOf(i interface{}) Type {
}
func PtrTo(t Type) Type {
if t.Kind() == Ptr {
panic("reflect: cannot make **T type")
}
ptrType := t.(rawType)<<5 | 5 // 0b0101 == 5
if ptrType>>5 != t {
panic("reflect: PtrTo type does not fit")
+1 -10
View File
@@ -724,14 +724,8 @@ func Zero(typ Type) Value {
panic("unimplemented: reflect.Zero()")
}
// New is the reflect equivalent of the new(T) keyword, returning a pointer to a
// new value of the given type.
func New(typ Type) Value {
return Value{
typecode: PtrTo(typ).(rawType),
value: alloc(typ.Size()),
flags: valueFlagExported,
}
panic("unimplemented: reflect.New()")
}
type funcHeader struct {
@@ -762,9 +756,6 @@ func (e *ValueError) Error() string {
// llvm.memcpy.p0i8.p0i8.i32().
func memcpy(dst, src unsafe.Pointer, size uintptr)
//go:linkname alloc runtime.alloc
func alloc(size uintptr) unsafe.Pointer
// Copy copies the contents of src into dst until either
// dst has been filled or src has been exhausted.
func Copy(dst, src Value) int {
+3 -3
View File
@@ -16,13 +16,13 @@ type funcValue struct {
// funcValueWithSignature is used before the func lowering pass.
type funcValueWithSignature struct {
funcPtr uintptr // ptrtoint of the actual function pointer
signature *uint8 // external *i8 with a name identifying the function signature
funcPtr uintptr // ptrtoint of the actual function pointer
signature *typecodeID // pointer to identify this signature (the value is undef)
}
// getFuncPtr is a dummy function that may be used if the func lowering pass is
// not used. It is generally too slow but may be a useful fallback to debug the
// func lowering pass.
func getFuncPtr(val funcValue, signature *uint8) uintptr {
func getFuncPtr(val funcValue, signature *typecodeID) uintptr {
return (*funcValueWithSignature)(unsafe.Pointer(val.id)).funcPtr
}
-5
View File
@@ -112,11 +112,6 @@ type typecodeID struct {
length uintptr
methodSet *interfaceMethodInfo // nil or a GEP of an array
// The type that's a pointer to this type, nil if it is already a pointer.
// Keeping the type struct alive here is important so that values from
// reflect.New (which uses reflect.PtrTo) can be used in type asserts etc.
ptrTo *typecodeID
}
// structField is used by the compiler to pass information to the interface
+6 -6
View File
@@ -23,9 +23,7 @@ func GOROOT() string {
return "/usr/local/go"
}
// This is the default set of arguments, if nothing else has been set.
// This may be overriden by modifying this global at runtime init (for example,
// on Linux where there are real command line arguments).
// TODO: fill with real args.
var args = []string{"/proc/self/exe"}
//go:linkname os_runtime_args os.runtime_args
@@ -49,9 +47,6 @@ func memmove(dst, src unsafe.Pointer, size uintptr)
// llvm.memset.p0i8.i32(ptr, 0, size, false).
func memzero(ptr unsafe.Pointer, size uintptr)
//export strlen
func strlen(ptr unsafe.Pointer) uintptr
// Compare two same-size buffers for equality.
func memequal(x, y unsafe.Pointer, n uintptr) bool {
for i := uintptr(0); i < n; i++ {
@@ -94,3 +89,8 @@ func AdjustTimeOffset(offset int64) {
func os_sigpipe() {
runtimePanic("too many writes on closed pipe")
}
//go:linkname syscall_runtime_envs syscall.runtime_envs
func syscall_runtime_envs() []string {
return nil
}
-43
View File
@@ -1,43 +0,0 @@
// +build sam,atsame51,atsame51j19
package runtime
import (
"device/sam"
)
func initSERCOMClocks() {
// Turn on clock to SERCOM0 for UART0
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// sets the "slow" clock shared by all SERCOM
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOMX_SLOW].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM1
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM2
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM3
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM4
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM5
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
-53
View File
@@ -1,53 +0,0 @@
// +build sam,atsame5x,atsame54p20
package runtime
import (
"device/sam"
)
func initSERCOMClocks() {
// Turn on clock to SERCOM0 for UART0
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// sets the "slow" clock shared by all SERCOM
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOMX_SLOW].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM1
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM2
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM3
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM4
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM5
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM6
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM6_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
// Turn on clock to SERCOM7
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM7_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
-338
View File
@@ -1,338 +0,0 @@
// +build sam,atsame5x
package runtime
import (
"device/arm"
"device/sam"
"machine"
"runtime/interrupt"
"runtime/volatile"
)
type timeUnit int64
func postinit() {}
//export Reset_Handler
func main() {
preinit()
run()
abort()
}
func init() {
initClocks()
initRTC()
initSERCOMClocks()
initUSBClock()
initADCClock()
// connect to USB CDC interface
machine.UART0.Configure(machine.UARTConfig{})
}
func putchar(c byte) {
machine.UART0.WriteByte(c)
}
func initClocks() {
// set flash wait state
sam.NVMCTRL.CTRLA.SetBits(0 << sam.NVMCTRL_CTRLA_RWS_Pos)
// software reset
sam.GCLK.CTRLA.SetBits(sam.GCLK_CTRLA_SWRST)
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_SWRST) {
}
// Set OSCULP32K as source of Generic Clock Generator 3
// GCLK->GENCTRL[GENERIC_CLOCK_GENERATOR_XOSC32K].reg = GCLK_GENCTRL_SRC(GCLK_GENCTRL_SRC_OSCULP32K) | GCLK_GENCTRL_GENEN; //generic clock gen 3
sam.GCLK.GENCTRL[3].Set((sam.GCLK_GENCTRL_SRC_OSCULP32K << sam.GCLK_GENCTRL_SRC_Pos) |
sam.GCLK_GENCTRL_GENEN)
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK3) {
}
// Set OSCULP32K as source of Generic Clock Generator 0
sam.GCLK.GENCTRL[0].Set((sam.GCLK_GENCTRL_SRC_OSCULP32K << sam.GCLK_GENCTRL_SRC_Pos) |
sam.GCLK_GENCTRL_GENEN)
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK0) {
}
// Enable DFLL48M clock
sam.OSCCTRL.DFLLCTRLA.Set(0)
sam.OSCCTRL.DFLLMUL.Set((0x1 << sam.OSCCTRL_DFLLMUL_CSTEP_Pos) |
(0x1 << sam.OSCCTRL_DFLLMUL_FSTEP_Pos) |
(0x0 << sam.OSCCTRL_DFLLMUL_MUL_Pos))
for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_DFLLMUL) {
}
sam.OSCCTRL.DFLLCTRLB.Set(0)
for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_DFLLCTRLB) {
}
sam.OSCCTRL.DFLLCTRLA.SetBits(sam.OSCCTRL_DFLLCTRLA_ENABLE)
for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_ENABLE) {
}
sam.OSCCTRL.DFLLVAL.Set(sam.OSCCTRL.DFLLVAL.Get())
for sam.OSCCTRL.DFLLSYNC.HasBits(sam.OSCCTRL_DFLLSYNC_DFLLVAL) {
}
sam.OSCCTRL.DFLLCTRLB.Set(sam.OSCCTRL_DFLLCTRLB_WAITLOCK |
sam.OSCCTRL_DFLLCTRLB_CCDIS |
sam.OSCCTRL_DFLLCTRLB_USBCRM)
for !sam.OSCCTRL.STATUS.HasBits(sam.OSCCTRL_STATUS_DFLLRDY) {
}
// set GCLK7 to run at 2MHz, using DFLL48M as clock source
// GCLK7 = 48MHz / 24 = 2MHz
sam.GCLK.GENCTRL[7].Set((sam.GCLK_GENCTRL_SRC_DFLL << sam.GCLK_GENCTRL_SRC_Pos) |
(24 << sam.GCLK_GENCTRL_DIV_Pos) |
sam.GCLK_GENCTRL_GENEN)
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK7) {
}
// Set up the PLLs
// Set PLL0 to run at 120MHz, using GCLK7 as clock source
sam.GCLK.PCHCTRL[1].Set(sam.GCLK_PCHCTRL_CHEN |
(sam.GCLK_PCHCTRL_GEN_GCLK7 << sam.GCLK_PCHCTRL_GEN_Pos))
// multiplier = 59 + 1 + (0/32) = 60
// PLL0 = 2MHz * 60 = 120MHz
sam.OSCCTRL.DPLL[0].DPLLRATIO.Set((0x0 << sam.OSCCTRL_DPLL_DPLLRATIO_LDRFRAC_Pos) |
(59 << sam.OSCCTRL_DPLL_DPLLRATIO_LDR_Pos))
for sam.OSCCTRL.DPLL[0].DPLLSYNCBUSY.HasBits(sam.OSCCTRL_DPLL_DPLLSYNCBUSY_DPLLRATIO) {
}
// MUST USE LBYPASS DUE TO BUG IN REV A OF SAMD51, via Adafruit lib.
sam.OSCCTRL.DPLL[0].DPLLCTRLB.Set((sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_GCLK << sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_Pos) |
sam.OSCCTRL_DPLL_DPLLCTRLB_LBYPASS)
sam.OSCCTRL.DPLL[0].DPLLCTRLA.Set(sam.OSCCTRL_DPLL_DPLLCTRLA_ENABLE)
for !sam.OSCCTRL.DPLL[0].DPLLSTATUS.HasBits(sam.OSCCTRL_DPLL_DPLLSTATUS_CLKRDY) ||
!sam.OSCCTRL.DPLL[0].DPLLSTATUS.HasBits(sam.OSCCTRL_DPLL_DPLLSTATUS_LOCK) {
}
// Set PLL1 to run at 100MHz, using GCLK7 as clock source
sam.GCLK.PCHCTRL[2].Set(sam.GCLK_PCHCTRL_CHEN |
(sam.GCLK_PCHCTRL_GEN_GCLK7 << sam.GCLK_PCHCTRL_GEN_Pos))
// multiplier = 49 + 1 + (0/32) = 50
// PLL1 = 2MHz * 50 = 100MHz
sam.OSCCTRL.DPLL[1].DPLLRATIO.Set((0x0 << sam.OSCCTRL_DPLL_DPLLRATIO_LDRFRAC_Pos) |
(49 << sam.OSCCTRL_DPLL_DPLLRATIO_LDR_Pos))
for sam.OSCCTRL.DPLL[1].DPLLSYNCBUSY.HasBits(sam.OSCCTRL_DPLL_DPLLSYNCBUSY_DPLLRATIO) {
}
// // MUST USE LBYPASS DUE TO BUG IN REV A OF SAMD51
sam.OSCCTRL.DPLL[1].DPLLCTRLB.Set((sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_GCLK << sam.OSCCTRL_DPLL_DPLLCTRLB_REFCLK_Pos) |
sam.OSCCTRL_DPLL_DPLLCTRLB_LBYPASS)
sam.OSCCTRL.DPLL[1].DPLLCTRLA.Set(sam.OSCCTRL_DPLL_DPLLCTRLA_ENABLE)
// for !sam.OSCCTRL.DPLLSTATUS1.HasBits(sam.OSCCTRL_DPLLSTATUS_CLKRDY) ||
// !sam.OSCCTRL.DPLLSTATUS1.HasBits(sam.OSCCTRL_DPLLSTATUS_LOCK) {
// }
// Set up the peripheral clocks
// Set 48MHZ CLOCK FOR USB
sam.GCLK.GENCTRL[1].Set((sam.GCLK_GENCTRL_SRC_DFLL << sam.GCLK_GENCTRL_SRC_Pos) |
sam.GCLK_GENCTRL_IDC |
sam.GCLK_GENCTRL_GENEN)
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK1) {
}
// // Set 100MHZ CLOCK FOR OTHER PERIPHERALS
// sam.GCLK.GENCTRL2.Set((sam.GCLK_GENCTRL_SRC_DPLL1 << sam.GCLK_GENCTRL_SRC_Pos) |
// sam.GCLK_GENCTRL_IDC |
// sam.GCLK_GENCTRL_GENEN)
// for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL2) {
// }
// // Set 12MHZ CLOCK FOR DAC
sam.GCLK.GENCTRL[4].Set((sam.GCLK_GENCTRL_SRC_DFLL << sam.GCLK_GENCTRL_SRC_Pos) |
sam.GCLK_GENCTRL_IDC |
(4 << sam.GCLK_GENCTRL_DIVSEL_Pos) |
sam.GCLK_GENCTRL_GENEN)
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK4) {
}
// // Set up main clock
sam.GCLK.GENCTRL[0].Set((sam.GCLK_GENCTRL_SRC_DPLL0 << sam.GCLK_GENCTRL_SRC_Pos) |
sam.GCLK_GENCTRL_IDC |
sam.GCLK_GENCTRL_GENEN)
for sam.GCLK.SYNCBUSY.HasBits(sam.GCLK_SYNCBUSY_GENCTRL_GCLK0) {
}
sam.MCLK.CPUDIV.Set(sam.MCLK_CPUDIV_DIV_DIV1)
// Use the LDO regulator by default
sam.SUPC.VREG.ClearBits(sam.SUPC_VREG_SEL)
// Start up the "Debug Watchpoint and Trace" unit, so that we can use
// it's 32bit cycle counter for timing.
//CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
//DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
func initRTC() {
// turn on digital interface clock
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_RTC_)
// disable RTC
sam.RTC_MODE0.CTRLA.ClearBits(sam.RTC_MODE0_CTRLA_ENABLE)
//sam.RTC_MODE0.CTRLA.Set(0)
for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_ENABLE) {
}
// reset RTC
sam.RTC_MODE0.CTRLA.SetBits(sam.RTC_MODE0_CTRLA_SWRST)
for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_SWRST) {
}
// set to use ulp 32k oscillator
sam.OSC32KCTRL.OSCULP32K.SetBits(sam.OSC32KCTRL_OSCULP32K_EN32K)
sam.OSC32KCTRL.RTCCTRL.Set(sam.OSC32KCTRL_RTCCTRL_RTCSEL_ULP32K)
// set Mode0 to 32-bit counter (mode 0) with prescaler 1 and GCLK2 is 32KHz/1
sam.RTC_MODE0.CTRLA.Set((sam.RTC_MODE0_CTRLA_MODE_COUNT32 << sam.RTC_MODE0_CTRLA_MODE_Pos) |
(sam.RTC_MODE0_CTRLA_PRESCALER_DIV1 << sam.RTC_MODE0_CTRLA_PRESCALER_Pos) |
(sam.RTC_MODE0_CTRLA_COUNTSYNC))
// re-enable RTC
sam.RTC_MODE0.CTRLA.SetBits(sam.RTC_MODE0_CTRLA_ENABLE)
for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_ENABLE) {
}
irq := interrupt.New(sam.IRQ_RTC, func(interrupt.Interrupt) {
// disable IRQ for CMP0 compare
sam.RTC_MODE0.INTFLAG.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
timerWakeup.Set(1)
})
irq.SetPriority(0xc0)
irq.Enable()
}
func waitForSync() {
for sam.RTC_MODE0.SYNCBUSY.HasBits(sam.RTC_MODE0_SYNCBUSY_COUNT) {
}
}
var (
timestamp timeUnit // ticks since boottime
timerLastCounter uint64
)
var timerWakeup volatile.Register8
const asyncScheduler = false
// ticksToNanoseconds converts RTC ticks (at 32768Hz) to nanoseconds.
func ticksToNanoseconds(ticks timeUnit) int64 {
// The following calculation is actually the following, but with both sides
// reduced to reduce the risk of overflow:
// ticks * 1e9 / 32768
return int64(ticks) * 1953125 / 64
}
// nanosecondsToTicks converts nanoseconds to RTC ticks (running at 32768Hz).
func nanosecondsToTicks(ns int64) timeUnit {
// The following calculation is actually the following, but with both sides
// reduced to reduce the risk of overflow:
// ns * 32768 / 1e9
return timeUnit(ns * 64 / 1953125)
}
// sleepTicks should sleep for d number of microseconds.
func sleepTicks(d timeUnit) {
for d != 0 {
ticks() // update timestamp
ticks := uint32(d)
if !timerSleep(ticks) {
return
}
d -= timeUnit(ticks)
}
}
// ticks returns number of microseconds since start.
func ticks() timeUnit {
waitForSync()
rtcCounter := uint64(sam.RTC_MODE0.COUNT.Get())
offset := (rtcCounter - timerLastCounter) // change since last measurement
timerLastCounter = rtcCounter
timestamp += timeUnit(offset)
return timestamp
}
// ticks are in microseconds
// Returns true if the timer completed.
// Returns false if another interrupt occured which requires an early return to scheduler.
func timerSleep(ticks uint32) bool {
timerWakeup.Set(0)
if ticks < 8 {
// due to delay waiting for the register value to sync, the minimum sleep value
// for the SAMD51 is 260us.
// For related info for SAMD21, see:
// https://community.atmel.com/comment/2507091#comment-2507091
ticks = 8
}
// request read of count
waitForSync()
// set compare value
cnt := sam.RTC_MODE0.COUNT.Get()
sam.RTC_MODE0.COMP[0].Set(uint32(cnt) + ticks)
// enable IRQ for CMP0 compare
sam.RTC_MODE0.INTENSET.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
wait:
waitForEvents()
if timerWakeup.Get() != 0 {
return true
}
if hasScheduler {
// The interurpt may have awoken a goroutine, so bail out early.
// Disable IRQ for CMP0 compare.
sam.RTC_MODE0.INTENCLR.SetBits(sam.RTC_MODE0_INTENSET_CMP0)
return false
} else {
// This is running without a scheduler.
// The application expects this to sleep the whole time.
goto wait
}
}
func initUSBClock() {
// Turn on clock(s) for USB
//MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB;
//MCLK->AHBMASK.reg |= MCLK_AHBMASK_USB;
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_USB_)
sam.MCLK.AHBMASK.SetBits(sam.MCLK_AHBMASK_USB_)
// Put Generic Clock Generator 1 as source for USB
//GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_USB].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
func initADCClock() {
// Turn on clocks for ADC0/ADC1.
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_ADC0_)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_ADC1_)
// Put Generic Clock Generator 1 as source for ADC0 and ADC1.
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_ADC0].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_ADC1].Set((sam.GCLK_PCHCTRL_GEN_GCLK1 << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
func waitForEvents() {
arm.Asm("wfe")
}
+1 -1
View File
@@ -27,7 +27,7 @@ func waitForEvents() {
if nrf.DEVICE == "nrf51" {
// sd_app_evt_wait: SOC_SVC_BASE_NOT_AVAILABLE + 29
arm.SVCall0(0x2B + 29)
} else if nrf.DEVICE == "nrf52" || nrf.DEVICE == "nrf52840" || nrf.DEVICE == "nrf52833" {
} else if nrf.DEVICE == "nrf52" || nrf.DEVICE == "nrf52840" {
// sd_app_evt_wait: SOC_SVC_BASE_NOT_AVAILABLE + 21
arm.SVCall0(0x2C + 21)
} else {
+1 -57
View File
@@ -43,34 +43,9 @@ func postinit() {}
// Entry point for Go. Initialize all packages and call main.main().
//export main
func main(argc int32, argv *unsafe.Pointer) int {
func main() int {
preinit()
// Make args global big enough so that it can store all command line
// arguments. Unfortunately this has to be done with some magic as the heap
// is not yet initialized.
argsSlice := (*struct {
ptr unsafe.Pointer
len uintptr
cap uintptr
})(unsafe.Pointer(&args))
argsSlice.ptr = malloc(uintptr(argc) * (unsafe.Sizeof(uintptr(0))) * 3)
argsSlice.len = 0
argsSlice.cap = uintptr(argc)
// Initialize command line parameters.
for *argv != nil {
// Convert the C string to a Go string.
length := strlen(*argv)
argString := _string{
length: length,
ptr: (*byte)(*argv),
}
args = append(args, *(*string)(unsafe.Pointer(&argString)))
// This is the Go equivalent of "argc++" in C.
argv = (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(argv)) + unsafe.Sizeof(argv)))
}
// Obtain the initial stack pointer right before calling the run() function.
// The run function has been moved to a separate (non-inlined) function so
// that the correct stack pointer is read.
@@ -87,37 +62,6 @@ func runMain() {
run()
}
//go:extern environ
var environ *unsafe.Pointer
//go:linkname syscall_runtime_envs syscall.runtime_envs
func syscall_runtime_envs() []string {
// Count how many environment variables there are.
env := environ
numEnvs := 0
for *env != nil {
numEnvs++
env = (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(env)) + unsafe.Sizeof(environ)))
}
// Create a string slice of all environment variables.
// This requires just a single heap allocation.
env = environ
envs := make([]string, 0, numEnvs)
for *env != nil {
ptr := *env
length := strlen(ptr)
s := _string{
ptr: (*byte)(ptr),
length: length,
}
envs = append(envs, *(*string)(unsafe.Pointer(&s)))
env = (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(env)) + unsafe.Sizeof(environ)))
}
return envs
}
func putchar(c byte) {
_putchar(int(c))
}
-11
View File
@@ -16,12 +16,6 @@ type __wasi_iovec_t struct {
//export fd_write
func fd_write(id uint32, iovs *__wasi_iovec_t, iovs_len uint, nwritten *uint) (errno uint)
// See:
// https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-proc_exitrval-exitcode
//go:wasm-module wasi_snapshot_preview1
//export proc_exit
func proc_exit(exitcode uint32)
func postinit() {}
const (
@@ -55,11 +49,6 @@ func abort() {
trap()
}
//go:linkname syscall_Exit syscall.Exit
func syscall_Exit(code int) {
proc_exit(uint32(code))
}
// TinyGo does not yet support any form of parallelism on WebAssembly, so these
// can be left empty.
-5
View File
@@ -15,11 +15,6 @@ func _start() {
run()
}
//go:linkname syscall_runtime_envs syscall.runtime_envs
func syscall_runtime_envs() []string {
return nil
}
var handleEvent func()
//go:linkname setEventHandler syscall/js.setEventHandler
+1 -36
View File
@@ -21,33 +21,6 @@ func _start() {
run()
}
// Read the command line arguments from WASI.
// For example, they can be passed to a program with wasmtime like this:
//
// wasmtime ./program.wasm arg1 arg2
func init() {
// Read the number of args (argc) and the buffer size required to store all
// these args (argv).
var argc, argv_buf_size uint32
args_sizes_get(&argc, &argv_buf_size)
// Obtain the command line arguments
argsSlice := make([]unsafe.Pointer, argc)
buf := make([]byte, argv_buf_size)
args_get(&argsSlice[0], unsafe.Pointer(&buf[0]))
// Convert the array of C strings to an array of Go strings.
args = make([]string, argc)
for i, cstr := range argsSlice {
length := strlen(cstr)
argString := _string{
length: length,
ptr: (*byte)(cstr),
}
args[i] = *(*string)(unsafe.Pointer(&argString))
}
}
func ticksToNanoseconds(ticks timeUnit) int64 {
return int64(ticks)
}
@@ -89,15 +62,7 @@ func ticks() timeUnit {
return timeUnit(nano)
}
// Implementations of WASI APIs
//go:wasm-module wasi_snapshot_preview1
//export args_get
func args_get(argv *unsafe.Pointer, argv_buf unsafe.Pointer) (errno uint16)
//go:wasm-module wasi_snapshot_preview1
//export args_sizes_get
func args_sizes_get(argc *uint32, argv_buf_size *uint32) (errno uint16)
// Implementations of wasi_unstable APIs
//go:wasm-module wasi_snapshot_preview1
//export clock_time_get
-8
View File
@@ -1,8 +0,0 @@
{
"inherits": ["atmega1280"],
"build-tags": ["arduino_mega1280"],
"ldflags": [
"-Wl,--defsym=_bootloader_size=4096"
],
"flash-command":"avrdude -c arduino -b 57600 -p atmega1280 -P {port} -U flash:w:{hex}:i -v -D"
}
-17
View File
@@ -1,17 +0,0 @@
{
"inherits": ["avr"],
"cpu": "atmega1280",
"build-tags": ["atmega1280", "atmega"],
"cflags": [
"-mmcu=atmega1280"
],
"ldflags": [
"-mmcu=avr51",
"-Wl,--defsym=_stack_size=512"
],
"linkerscript": "src/device/avr/atmega1280.ld",
"extra-files": [
"targets/avr.S",
"src/device/avr/atmega1280.s"
]
}
+6 -1
View File
@@ -1,6 +1,11 @@
{
"inherits": ["cortex-m0plus"],
"inherits": ["cortex-m"],
"llvm-target": "armv6m-none-eabi",
"build-tags": ["atsamd21e18a", "atsamd21e18", "atsamd21", "sam"],
"cflags": [
"--target=armv6m-none-eabi",
"-Qunused-arguments"
],
"linkerscript": "targets/atsamd21.ld",
"extra-files": [
"src/device/sam/atsamd21e18a.s"
+6 -1
View File
@@ -1,6 +1,11 @@
{
"inherits": ["cortex-m0plus"],
"inherits": ["cortex-m"],
"llvm-target": "armv6m-none-eabi",
"build-tags": ["atsamd21g18a", "atsamd21g18", "atsamd21", "sam"],
"cflags": [
"--target=armv6m-none-eabi",
"-Qunused-arguments"
],
"linkerscript": "targets/atsamd21.ld",
"extra-files": [
"src/device/sam/atsamd21g18a.s"
+3
View File
@@ -1,6 +1,9 @@
{
"inherits": ["cortex-m4"],
"build-tags": ["atsamd51g19a", "atsamd51g19", "atsamd51", "sam"],
"cflags": [
"-Qunused-arguments"
],
"linkerscript": "targets/atsamd51.ld",
"extra-files": [
"src/device/sam/atsamd51g19a.s"
+3
View File
@@ -1,6 +1,9 @@
{
"inherits": ["cortex-m4"],
"build-tags": ["atsamd51j19a", "atsamd51j19", "atsamd51", "sam"],
"cflags": [
"-Qunused-arguments"
],
"linkerscript": "targets/atsamd51.ld",
"extra-files": [
"src/device/sam/atsamd51j19a.s"
+3
View File
@@ -1,6 +1,9 @@
{
"inherits": ["cortex-m4"],
"build-tags": ["sam", "atsamd51", "atsamd51j20", "atsamd51j20a"],
"cflags": [
"-Qunused-arguments"
],
"linkerscript": "targets/atsamd51j20a.ld",
"extra-files": [
"src/device/sam/atsamd51j20a.s"
+3
View File
@@ -1,6 +1,9 @@
{
"inherits": ["cortex-m4"],
"build-tags": ["atsamd51p19a", "atsamd51p19", "atsamd51", "sam"],
"cflags": [
"-Qunused-arguments"
],
"linkerscript": "targets/atsamd51.ld",
"extra-files": [
"src/device/sam/atsamd51p19a.s"
+3
View File
@@ -1,6 +1,9 @@
{
"inherits": ["cortex-m4"],
"build-tags": ["sam", "atsamd51", "atsamd51p20", "atsamd51p20a"],
"cflags": [
"-Qunused-arguments"
],
"linkerscript": "targets/atsamd51p20a.ld",
"extra-files": [
"src/device/sam/atsamd51p20a.s"
-10
View File
@@ -1,10 +0,0 @@
{
"inherits": ["cortex-m4"],
"build-tags": ["atsame51j19a", "atsame51j19", "atsame51", "atsame5x", "sam"],
"linkerscript": "targets/atsame5xx19.ld",
"extra-files": [
"src/device/sam/atsame51j19a.s"
],
"openocd-transport": "swd",
"openocd-target": "atsame5x"
}
-6
View File
@@ -1,6 +0,0 @@
{
"inherits": ["atsame54p20a"],
"build-tags": ["atsame54_xpro"],
"flash-method": "openocd",
"openocd-interface": "cmsis-dap"
}
-10
View File
@@ -1,10 +0,0 @@
{
"inherits": ["cortex-m4"],
"build-tags": ["sam", "atsame5x", "atsame54p20", "atsame54p20a"],
"linkerscript": "targets/atsame5xx20-no-bootloader.ld",
"extra-files": [
"src/device/sam/atsame54p20a.s"
],
"openocd-transport": "swd",
"openocd-target": "atsame5x"
}
-10
View File
@@ -1,10 +0,0 @@
MEMORY
{
FLASH_TEXT (rw) : ORIGIN = 0x00000000+0x4000, LENGTH = 0x00080000-0x4000 /* First 16KB used by bootloader */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x00030000
}
_stack_size = 4K;
INCLUDE "targets/arm.ld"
-10
View File
@@ -1,10 +0,0 @@
MEMORY
{
FLASH_TEXT (rw) : ORIGIN = 0x00000000+0x0000, LENGTH = 0x00100000-0x0000
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 0x00040000
}
_stack_size = 4K;
INCLUDE "targets/arm.ld"
+2 -1
View File
@@ -4,7 +4,8 @@
"build-tags": ["attiny85", "attiny", "avr2", "avr25"],
"cflags": [
"-mmcu=attiny85",
"-D__AVR_ARCH__=25"
"-D__AVR_ARCH__=25",
"-Qunused-arguments"
],
"ldflags": [
"-mmcu=avr25"
+2 -2
View File
@@ -3,13 +3,13 @@
"build-tags": ["avr", "baremetal", "linux", "arm"],
"goos": "linux",
"goarch": "arm",
"compiler": "clang",
"gc": "conservative",
"linker": "avr-gcc",
"scheduler": "none",
"default-stack-size": 256,
"cflags": [
"--target=avr-unknown-unknown",
"-Werror"
"--target=avr-unknown-unknown"
],
"ldflags": [
"-T", "targets/avr.ld",
+6 -1
View File
@@ -1,6 +1,11 @@
{
"inherits": ["cortex-m3"],
"inherits": ["cortex-m"],
"llvm-target": "armv7m-none-eabi",
"build-tags": ["bluepill", "stm32f103", "stm32f1", "stm32"],
"cflags": [
"--target=armv7m-none-eabi",
"-Qunused-arguments"
],
"linkerscript": "targets/stm32.ld",
"extra-files": [
"src/device/stm32/stm32f103.s"
+6 -1
View File
@@ -1,6 +1,11 @@
{
"inherits": ["cortex-m3"],
"inherits": ["cortex-m"],
"llvm-target": "armv7m-none-eabi",
"build-tags": ["qemu", "lm3s6965"],
"cflags": [
"--target=armv7m-none-eabi",
"-Qunused-arguments"
],
"linkerscript": "targets/lm3s6965.ld",
"extra-files": [
"targets/cortex-m-qemu.s"
+1
View File
@@ -2,6 +2,7 @@
"build-tags": ["cortexm", "baremetal", "linux", "arm"],
"goos": "linux",
"goarch": "arm",
"compiler": "clang",
"gc": "conservative",
"scheduler": "tasks",
"linker": "ld.lld",
+2 -1
View File
@@ -2,6 +2,7 @@
"inherits": ["cortex-m"],
"llvm-target": "armv6m-none-eabi",
"cflags": [
"--target=armv6m-none-eabi"
"--target=armv6m-none-eabi",
"-Qunused-arguments"
]
}
-7
View File
@@ -1,7 +0,0 @@
{
"inherits": ["cortex-m"],
"llvm-target": "armv6m-none-eabi",
"cflags": [
"--target=armv6m-none-eabi"
]
}
-7
View File
@@ -1,7 +0,0 @@
{
"inherits": ["cortex-m"],
"llvm-target": "armv7m-none-eabi",
"cflags": [
"--target=armv7m-none-eabi"
]
}
+2 -1
View File
@@ -3,6 +3,7 @@
"llvm-target": "armv7m-none-eabi",
"cflags": [
"--target=armv7m-none-eabi",
"-mfloat-abi=soft"
"-mfloat-abi=soft",
"-Qunused-arguments"
]
}
+2 -1
View File
@@ -3,6 +3,7 @@
"llvm-target": "armv7em-none-eabi",
"cflags": [
"--target=armv7em-none-eabi",
"-mfloat-abi=soft"
"-mfloat-abi=soft",
"-Qunused-arguments"
]
}

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