Compare commits

..

53 Commits

Author SHA1 Message Date
sago35 3591e194f7 machine: changed to block if no read data exists on UART and USB 2022-03-29 08:53:52 +09:00
sago35 cc3009b5c1 os, runtime: enable os.Stdin for baremetal target 2022-03-29 08:51:23 +09:00
Elliott Sales de Andrade f159573975 Add reflect.Value.FieldByIndexErr stub 2022-03-24 06:31:02 +01:00
sago35 234234af15 build: add JSON output to build command 2022-03-24 05:51:38 +01:00
Dmitriy 3d68804702 Add board support for ESP32-C3-12f Kit 2022-03-20 07:39:27 +01:00
Dan Kegel 38efca1e2d syscall: stub mmap(), munmap(), MAP_SHARED, PROT_READ, SIGBUS, etc. on nonhosted targets
Makes 1.18 tests a little happier.

Works around this error:

$ make test GOTESTFLAGS="-run TestTest/EmulatedCortexM3/Pass"
...
main_test.go:520: test error: could not compile: /usr/local/go/src/internal/fuzz/sys_posix.go:19:18: PROT_READ not declared by package syscall
2022-03-19 21:06:45 +01:00
Aayush Attri 0a75dd82b9 updating the comments for stub funcs 2022-03-19 19:09:20 +01:00
Aayush Attri fbc748f152 removing Version stub 2022-03-19 19:09:20 +01:00
Aayush Attri 881aba1785 add stub for runtime numcgocall, numgoroutine and version 2022-03-19 19:09:20 +01:00
Dan Kegel aa421bf655 compiler.go: createBuiltin: accept alias for slice. Helps 1.18 tests pass.
With proper fix by Ayke.
2022-03-19 19:05:57 +01:00
Dan Kegel 1fb1f08233 syscall: define MAP_SHARED and PROT_READ on wasi
Makes 1.18 tests a little happier.

Not sure mmap works on wasi, so these may be somewhat stubby.
2022-03-19 16:05:23 +01:00
ZauberNerd 0b5d300d94 targets/wasi: remove --export-dynamic linker flag
Exporting symbols seems to embed them in the WASM exports section which
causes wasmtime to fail: https://github.com/bytecodealliance/wasmtime/issues/2587
As a workaround, it is possible to specify the `--allow-unknown-exports`
flag on wasmtime.
But as discussed in the above linked issue, this seems to only be a
workaround. For the Rust compiler the fix was to remove the
`--export-dynamic` linker flag when targeting `wasm32-wasi`:
https://github.com/rust-lang/rust/pull/81255
Which is waht this commit does for Tinygo too.
2022-03-19 15:36:44 +01:00
ZauberNerd 2fdcabdcce src/runtime: add runtime.Version()
This adds the `Version()` function of the `runtime` package which embeds
the go version that was used to build tinygo.

For programs that are compiled with tinygo the version can be overriden
via the:
`tinygo build -ldflags="-X 'runtime.buildVersion=abc'"` flag.
Otherwise it will continue to use the go version with which tinygo was
compiled.
2022-03-19 15:36:44 +01:00
ZauberNerd d066b5c232 Move gitSha1 build time variable from main to goenv package
Moving and exporting this variable from the main to the goenv package
allows us to use it from both the main and the builder package.
This is done in preparation to include the value in `tinygo build`
linker flags, so that we can embed the version and git sha into binaries
built with tinygo.
2022-03-19 15:36:44 +01:00
Elliott Sales de Andrade 836ab95192 Rename reflect.Ptr to reflect.Pointer
This was done in plain Go for 1.18:
https://github.com/golang/go/commit/17910ed4ff5a3cb3dcf4367d4af23ad5a7fe5809
2022-03-18 15:27:28 +01:00
Dan Kegel cf8f4d65f2 Implement getpagesize and munmap. For go 1.18. 2022-03-18 13:44:30 +01:00
Damian Gryski 06b19cde2d interp: prevent an off-by-one during interp debug 2022-03-17 20:06:59 +01:00
Elliott Sales de Andrade 42ae9a665f os: Add some exec.ProcessState stubs 2022-03-17 12:33:59 +01:00
Dan Kegel c55c996c5d gc_leaking.go: don't inline alloc. Fixes #2674. 2022-03-17 11:26:01 +01:00
ZauberNerd 6fb90b6fc4 src/os: Add UserHomeDir() function to os package
This commit adds the `UserHomeDir()` function to the `os` package.
2022-03-16 22:19:05 +01:00
ZauberNerd 6f31712b7d test: write into a temp file and read from its fd
This test creates a new temp file and writes some bytes into it.
It then opens a new file for the file descriptor of the temp file and
tries to read some bytes out of it.
2022-03-16 15:40:04 +01:00
ZauberNerd e295770363 test: simple test to verify os.File.Fd() is working 2022-03-16 15:40:04 +01:00
ZauberNerd 486b99961d src/os: implement os.File.Fd() method
This commits adds a OS-specific `Fd()` function for `file_anyos.go` and
`file_other.go`, which returns a uintptr to the underlying file
descriptor.
2022-03-16 15:40:04 +01:00
Dan Kegel 4a98db4c86 Add regression test for #2666.
I didn't see how to run it easily from main_test.go, though I didn't try too hard.
And it doesn't really have a good place to go in Makefile.
So I added a new target tinygo-baremetal, and invoke it from CI at the end of assert-test-linux.
It only adds 7 seconds to the run, should be ok.
2022-03-15 05:59:00 +01:00
Dan Kegel c534fa1b6f On baremetal platforms, use simpler test matcher. Fixes #2666.
Uses same matcher in testdata (because now we can't replace it in testdata).
2022-03-15 05:59:00 +01:00
deadprogram eed78338e6 build: trigger builds of dev branches of repos in TinyGo ecosystem, e.g. Bluetooth, TinyFS, TinyFont, TinyDraw
Signed-off-by: deadprogram <ron@hybridgroup.com>
2022-03-14 20:44:43 +01:00
Elliott Sales de Andrade 5141638cbf Fix type of Signal constants on WASI 2022-03-13 12:53:23 +01:00
Elliott Sales de Andrade 5d4f795aec Add an empty os.Process.Signal implementation
This fixes compile of tests in Go 1.18, due to its use in
`src/internal/testenv/testenv.go`.
2022-03-13 12:53:23 +01:00
Elliott Sales de Andrade db8603e378 Add os Signal aliases
These are used in Go 1.18's `testing/internal/testdeps`. Though the
comment says they should exist _everywhere_, there is still a build
constraint, but that seems to be fine.
2022-03-13 12:53:23 +01:00
Elliott Sales de Andrade bc098da93f Implement all of os.Signal in arch-specific syscall
This is basically copied from `syscall_js.go` from the Go standard
library, since the existing parts were from there as well.
2022-03-13 12:53:23 +01:00
Ayke van Laethem e49e93f22c main: calculate default output path if -o is not specified
This matches the Go command and is generally convenient to have.
2022-03-13 01:08:20 +01:00
Ayke van Laethem 7d4bf09b1a builder: use correct permission bits when creating a library
Previously, the wrong permission bits were emitted by
`tinygo build-library`. This commit fixes that, by `chmod`'ing to
reasonable default permission bits.
2022-03-12 23:20:38 +01:00
Ayke van Laethem 320f21524e cgo: slightly improve error messages
Updating them to libclang-13-dev was a good change, but we can go even
further:

  * The suggestion didn't apply to MacOS.
  * The suggestion would need to be updated with every LLVM release,
    which is a maintenance burden.
  * The suggestion is wrong when compiling with `-tags=llvm12` for
    example to choose a different LLVM version.

Therefore, link to the build documentation instead.
2022-03-12 21:17:29 +01:00
Dan Kegel 4117055611 Makefile: chmod before fpm. For #2685 2022-03-12 17:24:16 +01:00
Ayke van Laethem 603fff78d4 all: add support for ThinLTO
ThinLTO optimizes across LLVM modules at link time. This means that
optimizations (such as inlining and const-propagation) are possible
between C and Go. This makes this change especially useful for CGo, but
not just for CGo. By doing some optimizations at link time, the linker
can discard some unused functions and this leads to a size reduction on
average. It does increase code size in some cases, but that's true for
most optimizations.

I've excluded a number of targets for now (wasm, avr, xtensa, windows,
macos). They can probably be supported with some more work, but that
should be done in separate PRs.

Overall, this change results in an average 3.24% size reduction over all
the tinygo.org/x/drivers smoke tests.

TODO: this commit runs part of the pass pipeline twice. We should set
the PrepareForThinLTO flag in the PassManagerBuilder for even further
reduced code size (0.7%) and improved compilation speed.
2022-03-12 12:55:38 +01:00
Ayke van Laethem d4b1467e4c build: support machine outlining pass in stacksize calculation
The machine outliner introduces a few new opcodes that weren't
previously emitted by LLVM. We need to support these.

This doesn't trigger very often, but it sometimes does. It triggers a
lot more often with ThinLTO enabled.
2022-03-12 12:55:38 +01:00
ZauberNerd 4cf8ad2bee Update libclang installation comment to libclang-13-dev
Tinygo bumped the default llvm version to v13 in:
tinygo-org/tinygo@3a4e0c9
2022-03-12 09:31:18 +01:00
sago35 96c60f9692 atsamd51: allow faster frequency setting when using SPI 2022-03-12 08:45:38 +01:00
Elliott Sales de Andrade 99ce46669b Fix LLVM build constraints 2022-03-11 07:51:44 +01:00
sago35 a1b4eafa07 samd21,samd51: fix usbcdc initialization when -serial=uart (#2631)
machine/samd21,samd51: fix usbcdc initialization when -serial=uart by using machine.USB.Configured()
2022-03-10 12:32:19 +01:00
deadprogram ccbe03795a build/windows: use fork with updated permissions for new scoop 2022-03-10 09:13:33 +01:00
ZauberNerd 3f69c32a55 src/os: export correct values for os.DevNull for each OS
This commit introduces `os.DevNull` exports for all supported OS
targets.
2022-03-08 14:49:14 +01:00
Dmitriy b176494e44 add support for GPIO interrupts on esp32c3
Update interrupt_esp32c3.go:
make callHandler inline
save and restore MSTATUS along with MEPC
save and restore actual threshold value and call fence
print additional data during exception
2022-03-08 09:13:15 +01:00
ZauberNerd 0243a5b8be src/os: add stubs for exec.ExitError and ProcessState.ExitCode
This commit adds stubs for the `ExitError` struct of the `exec` package
and `ProcessState.ExitCode()` of the `os` package.

Since the `os/exec` is listed as unsupported, stubbing these methods
and structs should be enough to get programs that use these to compile.
2022-03-08 06:45:53 +01:00
ZauberNerd 1fac41d535 src/runtime: add stub for runtime.NumCPU()
This adds a stub for the `NumCPU()` function from the `runtime`
package.
This change allows code to compile that tries to access this function.

I guess for most hardware boards and WASM setting this value to `1` is
fine. And as far as I can see it shouldn't break or change existing
applications, because the function previously did not exist at all.
2022-03-07 21:03:38 +01:00
ZauberNerd 1472fb6032 src/runtime: add stub for debug.ReadBuildInfo()
This adds the necessary structs and the `ReadBuildInfo()` function to
the runtime/debug module to allow to compile code that tries to access
it.
The stub itself returns ok=false, so that calling code should not try
to read from the nil pointer that is returned instead of the actual
BuildInfo struct.
2022-03-07 20:03:51 +01:00
Samuel Stauffer 0fd3d785a3 syscall/js: allow copyBytesTo(Go|JS) to use Uint8ClampedArray
From https://github.com/golang/go/commit/f0e8b81aa34120e21642c569912bde00ccd33393

Fixes https://github.com/tinygo-org/tinygo/issues/1941
2022-03-07 19:01:55 +01:00
Ayke van Laethem b9c0aa77bf runtime: implement memhash
This function is used by the hash/maphash package.

Unfortunately, I couldn't get the hash/maphash package to pass tests
because it's too slow. I think it hits the quadratic complexity of the
current map implementation.
2022-03-06 10:13:04 +01:00
Ayke van Laethem 4c28f1b875 runtime: add fastrand
This is needed for hash/maphash support.
2022-03-06 10:13:04 +01:00
Dan Kegel 0791603c86 Makefile: add report-stdlib-tests-pass 2022-03-05 22:22:22 +01:00
Damian Gryski 095312fa3f src/syscall: document Environ() single-allocation tradeoff 2022-03-04 15:26:47 +01:00
Damian Gryski 7e647a5e81 src/runtime: use memzero for leaking collector 2022-03-04 01:35:22 +01:00
Ayke van Laethem 29c1d7c68d compiler: fix incorrect unsafe.Alignof on some 32-bit architectures
This should fix https://github.com/tinygo-org/tinygo/issues/2643
2022-03-04 00:04:17 +01:00
97 changed files with 1844 additions and 185 deletions
+24
View File
@@ -57,3 +57,27 @@ jobs:
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger Bluetooth repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/bluetooth/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger TinyFS repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinyfs/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger TinyFont repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinyfont/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
- name: Trigger TinyDraw repo build on CircleCI
run: |
curl --location --request POST 'https://circleci.com/api/v2/project/github/tinygo-org/tinydraw/pipeline' \
--header 'Content-Type: application/json' \
-d '{"branch": "dev"}' \
-u "${{ secrets.CIRCLECI_API_TOKEN }}"
+1
View File
@@ -239,3 +239,4 @@ jobs:
rm xtensa-esp32-elf-gcc8_2_0-esp-2020r2-linux-amd64.tar.gz
- run: make smoketest
- run: make wasmtest
- run: make tinygo-baremetal
+1 -1
View File
@@ -15,7 +15,7 @@ jobs:
uses: actions/setup-go@v2
with:
go-version: '1.17'
- uses: MinoruSekine/setup-scoop@v1
- uses: brechtm/setup-scoop@v2
- name: Install Dependencies
shell: bash
run: |
+46 -23
View File
@@ -208,19 +208,20 @@ lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a:
# Build the Go compiler.
tinygo:
@if [ ! -f "$(LLVM_BUILDDIR)/bin/llvm-config" ]; then echo "Fetch and build LLVM first by running:"; echo " make llvm-source"; echo " make $(LLVM_BUILDDIR)"; exit 1; fi
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X main.gitSha1=`git rev-parse --short HEAD`" .
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) build -buildmode exe -o build/tinygo$(EXE) -tags byollvm -ldflags="-X github.com/tinygo-org/tinygo/goenv.GitSha1=`git rev-parse --short HEAD`" .
test: wasi-libc
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=20m -buildmode exe -tags byollvm ./builder ./cgo ./compileopts ./compiler ./interp ./transform .
# Tests that take over a minute in wasi
# Standard library packages that pass tests on darwin, linux, wasi, and windows, but take over a minute in wasi
TEST_PACKAGES_SLOW = \
compress/bzip2 \
compress/flate \
crypto/dsa \
index/suffixarray \
TEST_PACKAGES_BASE = \
# Standard library packages that pass tests quickly on darwin, linux, wasi, and windows
TEST_PACKAGES_FAST = \
compress/lzw \
compress/zlib \
container/heap \
@@ -264,47 +265,63 @@ TEST_PACKAGES_BASE = \
unicode/utf16 \
unicode/utf8 \
# Standard library packages that pass tests natively
TEST_PACKAGES := \
$(TEST_PACKAGES_BASE)
# archive/zip requires ReadAt, which is not yet supported on windows
# archive/zip requires os.ReadAt, which is not yet supported on windows
# debug/plan9obj requires os.ReadAt, which is not yet supported on windows
# io/fs requires os.ReadDir, which is not yet supported on windows or wasi
# testing/fstest requires os.ReadDir, which is not yet supported on windows or wasi
ifneq ($(OS),Windows_NT)
TEST_PACKAGES := \
$(TEST_PACKAGES) \
# Additional standard library packages that pass tests on individual platforms
TEST_PACKAGES_LINUX := \
archive/zip \
debug/dwarf \
debug/plan9obj \
io/fs \
testing/fstest
endif
# Standard library packages that pass tests on wasi
TEST_PACKAGES_WASI = \
$(TEST_PACKAGES_BASE)
TEST_PACKAGES_DARWIN := $(TEST_PACKAGES_LINUX)
# Report platforms on which each standard library package is known to pass tests
jointmp := $(shell echo /tmp/join.$$$$)
report-stdlib-tests-pass:
@for t in $(TEST_PACKAGES_DARWIN); do echo "$$t darwin"; done | sort > $(jointmp).darwin
@for t in $(TEST_PACKAGES_LINUX); do echo "$$t linux"; done | sort > $(jointmp).linux
@for t in $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW); do echo "$$t darwin linux wasi windows"; done | sort > $(jointmp).portable
@join -a1 -a2 $(jointmp).darwin $(jointmp).linux | \
join -a1 -a2 - $(jointmp).portable
@rm $(jointmp).*
# Standard library packages that pass tests quickly on the current platform
ifeq ($(shell uname),Darwin)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_DARWIN)
endif
ifeq ($(shell uname),Linux)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_LINUX)
endif
ifeq ($(OS),Windows_NT)
TEST_PACKAGES_HOST := $(TEST_PACKAGES_FAST)
endif
# Test known-working standard library packages.
# TODO: parallelize, and only show failing tests (no implied -v flag).
.PHONY: tinygo-test
tinygo-test:
$(TINYGO) test $(TEST_PACKAGES) $(TEST_PACKAGES_SLOW)
$(TINYGO) test $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
tinygo-test-fast:
$(TINYGO) test $(TEST_PACKAGES)
$(TINYGO) test $(TEST_PACKAGES_HOST)
tinygo-bench:
$(TINYGO) test -bench . $(TEST_PACKAGES) $(TEST_PACKAGES_SLOW)
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST) $(TEST_PACKAGES_SLOW)
tinygo-bench-fast:
$(TINYGO) test -bench . $(TEST_PACKAGES)
$(TINYGO) test -bench . $(TEST_PACKAGES_HOST)
# Same thing, except for wasi rather than the current platform.
tinygo-test-wasi:
$(TINYGO) test -target wasi $(TEST_PACKAGES_WASI) $(TEST_PACKAGES_SLOW)
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
tinygo-test-wasi-fast:
$(TINYGO) test -target wasi $(TEST_PACKAGES_WASI)
$(TINYGO) test -target wasi $(TEST_PACKAGES_FAST)
tinygo-bench-wasi:
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_WASI) $(TEST_PACKAGES_SLOW)
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST) $(TEST_PACKAGES_SLOW)
tinygo-bench-wasi-fast:
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_WASI)
$(TINYGO) test -target wasi -bench . $(TEST_PACKAGES_FAST)
# Test external packages in a large corpus.
test-corpus:
@@ -314,6 +331,10 @@ test-corpus-fast:
test-corpus-wasi: wasi-libc
CGO_CPPFLAGS="$(CGO_CPPFLAGS)" CGO_CXXFLAGS="$(CGO_CXXFLAGS)" CGO_LDFLAGS="$(CGO_LDFLAGS)" $(GO) test $(GOTESTFLAGS) -timeout=1h -buildmode exe -tags byollvm -run TestCorpus . -corpus=testdata/corpus.yaml -target=wasi
tinygo-baremetal:
# Regression tests that run on a baremetal target and don't fit in either main_test.go or smoketest.
# regression test for #2666: e.g. encoding/hex must pass on baremetal
$(TINYGO) test -target cortex-m-qemu encoding/hex
.PHONY: smoketest
smoketest:
@@ -337,6 +358,8 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/echo
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/echo2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/i2s
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10040 examples/mcp3008
+64 -15
View File
@@ -105,6 +105,15 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
defer os.RemoveAll(dir)
}
// Look up the build cache directory, which is used to speed up incremental
// builds.
cacheDir := goenv.Get("GOCACHE")
if cacheDir == "off" {
// Use temporary build directory instead, effectively disabling the
// build cache.
cacheDir = dir
}
// Check for a libc dependency.
// As a side effect, this also creates the headers for the given libc, if
// the libc needs them.
@@ -195,6 +204,21 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
var packageJobs []*compileJob
packageBitcodePaths := make(map[string]string)
packageActionIDs := make(map[string]string)
if config.Options.GlobalValues["runtime"]["buildVersion"] == "" {
version := goenv.Version
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
}
if config.Options.GlobalValues == nil {
config.Options.GlobalValues = make(map[string]map[string]string)
}
if config.Options.GlobalValues["runtime"] == nil {
config.Options.GlobalValues["runtime"] = make(map[string]string)
}
config.Options.GlobalValues["runtime"]["buildVersion"] = version
}
for _, pkg := range lprogram.Sorted() {
pkg := pkg // necessary to avoid a race condition
@@ -238,12 +262,6 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Determine the path of the bitcode file (which is a serialized version
// of a LLVM module).
cacheDir := goenv.Get("GOCACHE")
if cacheDir == "off" {
// Use temporary build directory instead, effectively disabling the
// build cache.
cacheDir = dir
}
bitcodePath := filepath.Join(cacheDir, "pkg-"+hex.EncodeToString(hash[:])+".bc")
packageBitcodePaths[pkg.ImportPath] = bitcodePath
@@ -416,7 +434,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
// Load and link all the bitcode files. This does not yet optimize
// anything, it only links the bitcode files together.
ctx := llvm.NewContext()
mod = ctx.NewModule("")
mod = ctx.NewModule("main")
for _, pkg := range lprogram.Sorted() {
pkgMod, err := ctx.ParseBitcodeFile(packageBitcodePaths[pkg.ImportPath])
if err != nil {
@@ -512,8 +530,14 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
}
return ioutil.WriteFile(outpath, llvmBuf.Bytes(), 0666)
case ".bc":
data := llvm.WriteBitcodeToMemoryBuffer(mod).Bytes()
return ioutil.WriteFile(outpath, data, 0666)
var buf llvm.MemoryBuffer
if config.UseThinLTO() {
buf = llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
} else {
buf = llvm.WriteBitcodeToMemoryBuffer(mod)
}
defer buf.Dispose()
return ioutil.WriteFile(outpath, buf.Bytes(), 0666)
case ".ll":
data := []byte(mod.String())
return ioutil.WriteFile(outpath, data, 0666)
@@ -533,10 +557,17 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
dependencies: []*compileJob{programJob},
result: objfile,
run: func(*compileJob) error {
llvmBuf, err := machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
if err != nil {
return err
var llvmBuf llvm.MemoryBuffer
if config.UseThinLTO() {
llvmBuf = llvm.WriteThinLTOBitcodeToMemoryBuffer(mod)
} else {
var err error
llvmBuf, err = machine.EmitToMemoryBuffer(mod, llvm.ObjectFile)
if err != nil {
return err
}
}
defer llvmBuf.Dispose()
return ioutil.WriteFile(objfile, llvmBuf.Bytes(), 0666)
},
}
@@ -569,7 +600,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.UseThinLTO(), config.Options.PrintCommands)
job.result = result
return err
},
@@ -587,7 +618,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.UseThinLTO(), config.Options.PrintCommands)
job.result = result
return err
},
@@ -656,6 +687,24 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
if config.Options.PrintCommands != nil {
config.Options.PrintCommands(config.Target.Linker, ldflags...)
}
if config.UseThinLTO() {
ldflags = append(ldflags,
"--thinlto-cache-dir="+filepath.Join(cacheDir, "thinlto"),
"-plugin-opt=mcpu="+config.CPU(),
"-plugin-opt=O"+strconv.Itoa(optLevel),
"-plugin-opt=thinlto")
if config.CodeModel() != "default" {
ldflags = append(ldflags,
"-mllvm", "-code-model="+config.CodeModel())
}
if sizeLevel >= 2 {
// Workaround with roughly the same effect as
// https://reviews.llvm.org/D119342.
// Can hopefully be removed in LLVM 15.
ldflags = append(ldflags,
"-mllvm", "--rotation-max-header-size=0")
}
}
err = link(config.Target.Linker, ldflags...)
if err != nil {
return &commandError{"failed to link", executable, err}
@@ -846,7 +895,7 @@ func optimizeProgram(mod llvm.Module, config *compileopts.Config) error {
}
}
if config.GOOS() != "darwin" {
if config.GOOS() != "darwin" && !config.UseThinLTO() {
transform.ApplyFunctionSections(mod) // -ffunction-sections
}
+14 -6
View File
@@ -56,7 +56,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 func(string, ...string)) (string, error) {
func compileAndCacheCFile(abspath, tmpdir string, cflags []string, thinlto bool, printCommands func(string, ...string)) (string, error) {
// Hash input file.
fileHash, err := hashFile(abspath)
if err != nil {
@@ -67,6 +67,11 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
unlock := lock(filepath.Join(goenv.Get("GOCACHE"), fileHash+".c.lock"))
defer unlock()
ext := ".o"
if thinlto {
ext = ".bc"
}
// Create cache key for the dependencies file.
buf, err := json.Marshal(struct {
Path string
@@ -99,7 +104,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
}
// Obtain hashes of all the files listed as a dependency.
outpath, err := makeCFileCachePath(dependencies, depfileNameHash)
outpath, err := makeCFileCachePath(dependencies, depfileNameHash, ext)
if err == nil {
if _, err := os.Stat(outpath); err == nil {
return outpath, nil
@@ -112,7 +117,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
return "", err
}
objTmpFile, err := ioutil.TempFile(goenv.Get("GOCACHE"), "tmp-*.o")
objTmpFile, err := ioutil.TempFile(goenv.Get("GOCACHE"), "tmp-*"+ext)
if err != nil {
return "", err
}
@@ -124,6 +129,9 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
depTmpFile.Close()
flags := append([]string{}, cflags...) // copy cflags
flags = append(flags, "-MD", "-MV", "-MTdeps", "-MF", depTmpFile.Name()) // autogenerate dependencies
if thinlto {
flags = append(flags, "-flto=thin")
}
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
@@ -181,7 +189,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
}
// Move temporary object file to final location.
outpath, err := makeCFileCachePath(dependencySlice, depfileNameHash)
outpath, err := makeCFileCachePath(dependencySlice, depfileNameHash, ext)
if err != nil {
return "", err
}
@@ -196,7 +204,7 @@ func compileAndCacheCFile(abspath, tmpdir string, cflags []string, printCommands
// Create a cache path (a path in GOCACHE) to store the output of a compiler
// job. This path is based on the dep file name (which is a hash of metadata
// including compiler flags) and the hash of all input files in the paths slice.
func makeCFileCachePath(paths []string, depfileNameHash string) (string, error) {
func makeCFileCachePath(paths []string, depfileNameHash, ext string) (string, error) {
// Hash all input files.
fileHashes := make(map[string]string, len(paths))
for _, path := range paths {
@@ -221,7 +229,7 @@ func makeCFileCachePath(paths []string, depfileNameHash string) (string, error)
outFileNameBuf := sha512.Sum512_224(buf)
cacheKey := hex.EncodeToString(outFileNameBuf[:])
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+".o")
outpath := filepath.Join(goenv.Get("GOCACHE"), "obj-"+cacheKey+ext)
return outpath, nil
}
+8
View File
@@ -103,6 +103,10 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
if err != nil {
return nil, nil, err
}
err = os.Chmod(temporaryHeaderPath, 0o755) // TempDir uses 0o700 by default
if err != nil {
return nil, nil, err
}
err = os.Rename(temporaryHeaderPath, headerPath)
if err != nil {
switch {
@@ -182,6 +186,10 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
if err != nil {
return err
}
err = os.Chmod(f.Name(), 0o644) // TempFile uses 0o600 by default
if err != nil {
return err
}
// Store this archive in the cache.
return os.Rename(f.Name(), archiveFilePath)
},
+1 -1
View File
@@ -16,7 +16,7 @@ import (
)
/*
#include <clang-c/Index.h> // if this fails, install libclang-11-dev
#include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://tinygo.org/docs/guides/build/
#include <stdlib.h>
#include <stdint.h>
+4 -4
View File
@@ -5,12 +5,12 @@ package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-11/include
#cgo darwin amd64 CFLAGS: -I/usr/local/opt/llvm@11/include
#cgo darwin arm64 CFLAGS: -I/opt/homebrew/opt/llvm@11/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@11/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@11/include
#cgo freebsd CFLAGS: -I/usr/local/llvm11/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-11/lib -lclang
#cgo darwin amd64 LDFLAGS: -L/usr/local/opt/llvm@11/lib -lclang -lffi
#cgo darwin arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@11/lib -lclang -lffi
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@11/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@11/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm11/lib -lclang
*/
import "C"
+4 -4
View File
@@ -5,12 +5,12 @@ package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-12/include
#cgo darwin amd64 CFLAGS: -I/usr/local/opt/llvm@12/include
#cgo darwin arm64 CFLAGS: -I/opt/homebrew/opt/llvm@12/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@12/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@12/include
#cgo freebsd CFLAGS: -I/usr/local/llvm12/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-12/lib -lclang
#cgo darwin amd64 LDFLAGS: -L/usr/local/opt/llvm@12/lib -lclang -lffi
#cgo darwin arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@12/lib -lclang -lffi
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@12/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@12/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm12/lib -lclang
*/
import "C"
+4 -4
View File
@@ -5,12 +5,12 @@ package cgo
/*
#cgo linux CFLAGS: -I/usr/lib/llvm-13/include
#cgo darwin amd64 CFLAGS: -I/usr/local/opt/llvm@13/include
#cgo darwin arm64 CFLAGS: -I/opt/homebrew/opt/llvm@13/include
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@13/include
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@13/include
#cgo freebsd CFLAGS: -I/usr/local/llvm13/include
#cgo linux LDFLAGS: -L/usr/lib/llvm-13/lib -lclang
#cgo darwin amd64 LDFLAGS: -L/usr/local/opt/llvm@13/lib -lclang -lffi
#cgo darwin arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@13/lib -lclang -lffi
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@13/lib -lclang -lffi
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@13/lib -lclang -lffi
#cgo freebsd LDFLAGS: -L/usr/local/llvm13/lib -lclang
*/
import "C"
+1 -1
View File
@@ -3,7 +3,7 @@
// are slightly different from the ones defined in libclang.go, but they
// should be ABI compatible.
#include <clang-c/Index.h> // if this fails, install libclang-11-dev
#include <clang-c/Index.h> // If this fails, libclang headers aren't available. Please take a look here: https://tinygo.org/docs/guides/build/
CXCursor tinygo_clang_getTranslationUnitCursor(CXTranslationUnit tu) {
return clang_getTranslationUnitCursor(tu);
+51
View File
@@ -176,6 +176,34 @@ func (c *Config) AutomaticStackSize() bool {
return false
}
// UseThinLTO returns whether ThinLTO should be used for the given target. Some
// targets (such as wasm) are not yet supported.
// We should try and remove as many exceptions as possible in the future, so
// that this optimization can be applied in more places.
func (c *Config) UseThinLTO() bool {
parts := strings.Split(c.Triple(), "-")
if parts[0] == "wasm32" {
// wasm-ld doesn't seem to support ThinLTO yet.
return false
}
if parts[0] == "avr" || parts[0] == "xtensa" {
// These use external (GNU) linkers which might perhaps support ThinLTO
// through a plugin, but it's too much hassle to set up.
return false
}
if len(parts) >= 2 && strings.HasPrefix(parts[2], "macos") {
// We use an external linker here at the moment.
return false
}
if len(parts) >= 2 && parts[2] == "windows" {
// Linker error (undefined runtime.trackedGlobalsBitmap) when linking
// for Windows. Disable it for now until that's figured out and fixed.
return false
}
// Other architectures support ThinLTO.
return true
}
// RP2040BootPatch returns whether the RP2040 boot patch should be applied that
// calculates and patches in the checksum for the 2nd stage bootloader.
func (c *Config) RP2040BootPatch() bool {
@@ -217,6 +245,29 @@ func (c *Config) LibcPath(name string) (path string, precompiled bool) {
return filepath.Join(goenv.Get("GOCACHE"), name+"-"+archname), false
}
// DefaultBinaryExtension returns the default extension for binaries, such as
// .exe, .wasm, or no extension (depending on the target).
func (c *Config) DefaultBinaryExtension() string {
parts := strings.Split(c.Triple(), "-")
if parts[0] == "wasm32" {
// WebAssembly files always have the .wasm file extension.
return ".wasm"
}
if len(parts) >= 3 && parts[2] == "windows" {
// Windows uses .exe.
return ".exe"
}
if len(parts) >= 3 && parts[2] == "unknown" {
// There appears to be a convention to use the .elf file extension for
// ELF files intended for microcontrollers. I'm not aware of the origin
// of this, it's just something that is used by many projects.
// I think it's a good tradition, so let's keep it.
return ".elf"
}
// Linux, MacOS, etc, don't use a file extension. Use it as a fallback.
return ""
}
// CFlags returns the flags to pass to the C compiler. This is necessary for CGo
// preprocessing.
func (c *Config) CFlags() []string {
+3 -2
View File
@@ -32,8 +32,8 @@ type Options struct {
PrintIR bool
DumpSSA bool
VerifyIR bool
PrintCommands func(cmd string, args ...string)
Semaphore chan struct{} // -p flag controls cap
PrintCommands func(cmd string, args ...string) `json:"-"`
Semaphore chan struct{} `json:"-"` // -p flag controls cap
Debug bool
PrintSizes string
PrintAllocs *regexp.Regexp // regexp string
@@ -46,6 +46,7 @@ type Options struct {
OpenOCDCommands []string
LLVMFeatures string
Directory string
PrintJSON bool
}
// Verify performs a validation on the given options, raising an error if options are not valid.
+7 -2
View File
@@ -234,10 +234,15 @@ func Sizes(machine llvm.TargetMachine) types.Sizes {
panic("unknown pointer size")
}
// Construct a complex128 type because that's likely the type with the
// biggest alignment on most/all ABIs.
ctx := llvm.NewContext()
defer ctx.Dispose()
complex128Type := ctx.StructType([]llvm.Type{ctx.DoubleType(), ctx.DoubleType()}, false)
return &stdSizes{
IntSize: int64(intWidth / 8),
PtrSize: int64(targetData.PointerSize()),
MaxAlign: int64(targetData.PrefTypeAlignment(targetData.IntPtrType())),
MaxAlign: int64(targetData.ABITypeAlignment(complex128Type)),
}
}
@@ -1228,7 +1233,7 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
case "cap":
value := argValues[0]
var llvmCap llvm.Value
switch argTypes[0].(type) {
switch argTypes[0].Underlying().(type) {
case *types.Chan:
llvmCap = b.createRuntimeCall("chanCap", []llvm.Value{value}, "cap")
case *types.Slice:
+1 -1
View File
@@ -15,5 +15,5 @@ require (
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9
golang.org/x/tools v0.1.6-0.20210813165731-45389f592fe9
gopkg.in/yaml.v2 v2.4.0
tinygo.org/x/go-llvm v0.0.0-20220121152956-4fa2ab2718f3
tinygo.org/x/go-llvm v0.0.0-20220211075103-ee4aad45c3a1
)
+2 -2
View File
@@ -80,5 +80,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
tinygo.org/x/go-llvm v0.0.0-20220121152956-4fa2ab2718f3 h1:vQSFy0kNQegAfL/F6iyWQa4bF941Xc1gyJUkGy2m448=
tinygo.org/x/go-llvm v0.0.0-20220121152956-4fa2ab2718f3/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
tinygo.org/x/go-llvm v0.0.0-20220211075103-ee4aad45c3a1 h1:6G8AxueDdqobCEqQrmHPLaEH1AZ1p6Y7rGElDNT7N98=
tinygo.org/x/go-llvm v0.0.0-20220211075103-ee4aad45c3a1/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
+6
View File
@@ -14,6 +14,12 @@ import (
// Update this value before release of new version of software.
const Version = "0.23.0-dev"
var (
// This variable is set at build time using -ldflags parameters.
// See: https://stackoverflow.com/a/11355611
GitSha1 string
)
// GetGorootVersion returns the major and minor version for a given GOROOT path.
// If the goroot cannot be determined, (0, 0) is returned.
func GetGorootVersion(goroot string) (major, minor int, err error) {
+3 -3
View File
@@ -492,9 +492,9 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// Call a function with a definition available. Run it as usual,
// possibly trying to recover from it if it failed to execute.
if r.debug {
argStrings := make([]string, len(operands))
for i := range argStrings {
argStrings[i] = operands[i+1].String()
argStrings := make([]string, len(operands)-1)
for i, v := range operands[1:] {
argStrings[i] = v.String()
}
fmt.Fprintln(os.Stderr, indent+"call:", callFn.name+"("+strings.Join(argStrings, ", ")+")")
}
+34 -24
View File
@@ -36,12 +36,6 @@ import (
"go.bug.st/serial/enumerator"
)
var (
// This variable is set at build time using -ldflags parameters.
// See: https://stackoverflow.com/a/11355611
gitSha1 string
)
// commandError is an error type to wrap os/exec.Command errors. This provides
// some more information regarding what went wrong while running a command.
type commandError struct {
@@ -148,7 +142,27 @@ func Build(pkgName, outpath string, options *compileopts.Options) error {
return err
}
if options.PrintJSON {
b, err := json.MarshalIndent(config, "", " ")
if err != nil {
handleCompilerError(err)
}
fmt.Printf("%s\n", string(b))
return nil
}
return builder.Build(pkgName, outpath, config, func(result builder.BuildResult) error {
if outpath == "" {
if strings.HasSuffix(pkgName, ".go") {
// A Go file was specified directly on the command line.
// Base the binary name off of it.
outpath = filepath.Base(pkgName[:len(pkgName)-3]) + config.DefaultBinaryExtension()
} else {
// Pick a default output path based on the main directory.
outpath = filepath.Base(result.MainDir) + config.DefaultBinaryExtension()
}
}
if err := os.Rename(result.Binary, outpath); err != nil {
// Moving failed. Do a file copy.
inf, err := os.Open(result.Binary)
@@ -1012,8 +1026,8 @@ func getBMPPorts() (gdbPort, uartPort string, err error) {
func usage(command string) {
version := goenv.Version
if strings.HasSuffix(version, "-dev") && gitSha1 != "" {
version += "-" + gitSha1
if strings.HasSuffix(version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
}
switch command {
@@ -1208,13 +1222,13 @@ func main() {
llvmFeatures := flag.String("llvm-features", "", "comma separated LLVM features to enable")
cpuprofile := flag.String("cpuprofile", "", "cpuprofile output")
var flagJSON, flagDeps, flagTest *bool
if command == "help" || command == "list" || command == "info" {
flagJSON = flag.Bool("json", false, "print data in JSON format")
var flagJSON, flagDeps, flagTest bool
if command == "help" || command == "list" || command == "info" || command == "build" {
flag.BoolVar(&flagJSON, "json", false, "print data in JSON format")
}
if command == "help" || command == "list" {
flagDeps = flag.Bool("deps", false, "supply -deps flag to go list")
flagTest = flag.Bool("test", false, "supply -test flag to go list")
flag.BoolVar(&flagDeps, "deps", false, "supply -deps flag to go list")
flag.BoolVar(&flagTest, "test", false, "supply -test flag to go list")
}
var outpath string
if command == "help" || command == "build" || command == "build-library" || command == "test" {
@@ -1291,6 +1305,7 @@ func main() {
Programmer: *programmer,
OpenOCDCommands: ocdCommands,
LLVMFeatures: *llvmFeatures,
PrintJSON: flagJSON,
}
if *printCommands {
options.PrintCommands = printCommand
@@ -1319,11 +1334,6 @@ func main() {
switch command {
case "build":
if outpath == "" {
fmt.Fprintln(os.Stderr, "No output filename supplied (-o).")
usage(command)
os.Exit(1)
}
pkgName := "."
if flag.NArg() == 1 {
pkgName = filepath.ToSlash(flag.Arg(0))
@@ -1532,7 +1542,7 @@ func main() {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if *flagJSON {
if flagJSON {
json, _ := json.MarshalIndent(struct {
GOROOT string `json:"goroot"`
GOOS string `json:"goos"`
@@ -1571,13 +1581,13 @@ func main() {
os.Exit(1)
}
var extraArgs []string
if *flagJSON {
if flagJSON {
extraArgs = append(extraArgs, "-json")
}
if *flagDeps {
if flagDeps {
extraArgs = append(extraArgs, "-deps")
}
if *flagTest {
if flagTest {
extraArgs = append(extraArgs, "-test")
}
cmd, err := loader.List(config, extraArgs, flag.Args())
@@ -1614,8 +1624,8 @@ func main() {
goversion = s
}
version := goenv.Version
if strings.HasSuffix(goenv.Version, "-dev") && gitSha1 != "" {
version += "-" + gitSha1
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
}
fmt.Printf("tinygo version %s %s/%s (using go version %s and LLVM version %s)\n", version, runtime.GOOS, runtime.GOARCH, goversion, llvm.Version)
case "env":
+31
View File
@@ -0,0 +1,31 @@
// This is a echo console running on the os.Stdin and os.Stdout.
// Stdin and os.Stdout are connected to machine.Serial in the baremetal target.
//
// Serial can be switched with the -serial option as follows
// 1. tinygo flash -target wioterminal -serial usb examples/echo2
// 2. tinygo flash -target wioterminal -serial uart examples/echo2
//
// This example will also work with standard Go.
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
fmt.Printf("Echo console enabled. Type something then press enter:\r\n")
scanner := bufio.NewScanner(os.Stdin)
for {
msg := ""
fmt.Scanf("%s\n", &msg)
fmt.Printf("You typed (scanf) : %s\r\n", msg)
if scanner.Scan() {
fmt.Printf("You typed (scanner) : %s\r\n", scanner.Text())
}
}
}
+49
View File
@@ -0,0 +1,49 @@
//go:build esp32c312f
// +build esp32c312f
package machine
// Built-in RGB LED
const (
LED_RED = IO3
LED_GREEN = IO4
LED_BLUE = IO5
LED = LED_RED
)
const (
IO0 Pin = 0
IO1 Pin = 1
IO10 Pin = 10
IO18 Pin = 18
IO19 Pin = 19
IO2 Pin = 2
IO3 Pin = 3
IO4 Pin = 4
IO5 Pin = 5
IO6 Pin = 6
IO7 Pin = 7
IO8 Pin = 8
IO9 Pin = 9
RXD Pin = 20
TXD Pin = 21
)
// ADC pins
const (
ADC0 Pin = ADC1_0
ADC1 Pin = ADC2_0
ADC1_0 Pin = IO0
ADC1_1 Pin = IO1
ADC1_2 Pin = IO2
ADC1_3 Pin = IO3
ADC1_4 Pin = IO4
ADC2_0 Pin = IO5
)
// UART0 pins
const (
UART_TX_PIN = TXD
UART_RX_PIN = RXD
)
+8
View File
@@ -1742,6 +1742,7 @@ type USBCDC struct {
waitTxc bool
waitTxcRetryCount uint8
sent bool
configured bool
}
var (
@@ -1923,6 +1924,13 @@ func (usbcdc *USBCDC) Configure(config UARTConfig) {
// enable IRQ
intr := interrupt.New(sam.IRQ_USB, handleUSB)
intr.Enable()
usbcdc.configured = true
}
// Configured returns whether usbcdc is configured or not.
func (usbcdc *USBCDC) Configured() bool {
return usbcdc.configured
}
func handlePadCalibration() {
+27 -2
View File
@@ -1033,6 +1033,9 @@ func (uart *UART) Configure(config UARTConfig) error {
uart.Bus.CTRLA.Set((1 << sam.SERCOM_USART_INT_CTRLA_MODE_Pos) |
(1 << sam.SERCOM_USART_INT_CTRLA_SAMPR_Pos)) // sample rate of 16x
// set clock
setSERCOMClockGenerator(uart.SERCOM, sam.GCLK_PCHCTRL_GEN_GCLK1)
// Set baud rate
uart.SetBaudRate(config.BaudRate)
@@ -1124,7 +1127,8 @@ type I2CConfig struct {
const (
// SERCOM_FREQ_REF is always reference frequency on SAMD51 regardless of CPU speed.
SERCOM_FREQ_REF = 48000000
SERCOM_FREQ_REF = 48000000
SERCOM_FREQ_REF_GCLK0 = 120000000
// Default rise time in nanoseconds, based on 4.7K ohm pull up resistors
riseTimeNanoseconds = 125
@@ -1178,6 +1182,9 @@ func (i2c *I2C) Configure(config I2CConfig) error {
i2c.Bus.SYNCBUSY.HasBits(sam.SERCOM_I2CM_SYNCBUSY_SWRST) {
}
// set clock
setSERCOMClockGenerator(i2c.SERCOM, sam.GCLK_PCHCTRL_GEN_GCLK1)
// Set i2c controller mode
//SERCOM_I2CM_CTRLA_MODE( I2C_MASTER_OPERATION )
// sam.SERCOM_I2CM_CTRLA_MODE_I2C_MASTER = 5?
@@ -1483,8 +1490,18 @@ func (spi SPI) Configure(config SPIConfig) error {
spi.Bus.CTRLA.ClearBits(sam.SERCOM_SPIM_CTRLA_CPOL)
}
// set clock
freqRef := uint32(0)
if config.Frequency > SERCOM_FREQ_REF/2 {
setSERCOMClockGenerator(spi.SERCOM, sam.GCLK_PCHCTRL_GEN_GCLK0)
freqRef = uint32(SERCOM_FREQ_REF_GCLK0)
} else {
setSERCOMClockGenerator(spi.SERCOM, sam.GCLK_PCHCTRL_GEN_GCLK1)
freqRef = uint32(SERCOM_FREQ_REF)
}
// Set synch speed for SPI
baudRate := SERCOM_FREQ_REF / (2 * config.Frequency)
baudRate := freqRef / (2 * config.Frequency)
if baudRate > 0 {
baudRate--
}
@@ -1965,6 +1982,7 @@ type USBCDC struct {
waitTxc bool
waitTxcRetryCount uint8
sent bool
configured bool
}
var (
@@ -2149,6 +2167,13 @@ func (usbcdc *USBCDC) Configure(config UARTConfig) {
interrupt.New(sam.IRQ_USB_SOF_HSOF, handleUSBIRQ).Enable()
interrupt.New(sam.IRQ_USB_TRCPT0, handleUSBIRQ).Enable()
interrupt.New(sam.IRQ_USB_TRCPT1, handleUSBIRQ).Enable()
usbcdc.configured = true
}
// Configured returns whether usbcdc is configured or not.
func (usbcdc *USBCDC) Configured() bool {
return usbcdc.configured
}
func handlePadCalibration() {
+36
View File
@@ -28,6 +28,42 @@ var (
sercomSPIM5 = SPI{Bus: sam.SERCOM5_SPIM, SERCOM: 5}
)
// setSERCOMClockGenerator sets the GCLK for sercom
func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
switch sercom {
case 0:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 1:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 2:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 3:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 4:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 5:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
}
// This chip has three TCC peripherals, which have PWM as one feature.
var (
TCC0 = (*TCC)(sam.TCC0)
+36
View File
@@ -28,6 +28,42 @@ var (
sercomSPIM5 = SPI{Bus: sam.SERCOM5_SPIM, SERCOM: 5}
)
// setSERCOMClockGenerator sets the GCLK for sercom
func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
switch sercom {
case 0:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 1:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 2:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 3:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 4:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 5:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
}
// This chip has five TCC peripherals, which have PWM as one feature.
var (
TCC0 = (*TCC)(sam.TCC0)
+36
View File
@@ -28,6 +28,42 @@ var (
sercomSPIM5 = SPI{Bus: sam.SERCOM5_SPIM, SERCOM: 5}
)
// setSERCOMClockGenerator sets the GCLK for sercom
func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
switch sercom {
case 0:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 1:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 2:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 3:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 4:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 5:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
}
// This chip has five TCC peripherals, which have PWM as one feature.
var (
TCC0 = (*TCC)(sam.TCC0)
+46
View File
@@ -32,6 +32,52 @@ var (
sercomSPIM7 = SPI{Bus: sam.SERCOM7_SPIM, SERCOM: 7}
)
// setSERCOMClockGenerator sets the GCLK for sercom
func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
switch sercom {
case 0:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 1:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 2:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 3:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 4:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 5:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 6:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM6_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 7:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM7_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
}
// This chip has five TCC peripherals, which have PWM as one feature.
var (
TCC0 = (*TCC)(sam.TCC0)
+46
View File
@@ -32,6 +32,52 @@ var (
sercomSPIM7 = SPI{Bus: sam.SERCOM7_SPIM, SERCOM: 7}
)
// setSERCOMClockGenerator sets the GCLK for sercom
func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
switch sercom {
case 0:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 1:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 2:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 3:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 4:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 5:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 6:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM6_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 7:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM7_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
}
// This chip has five TCC peripherals, which have PWM as one feature.
var (
TCC0 = (*TCC)(sam.TCC0)
+36
View File
@@ -28,6 +28,42 @@ var (
sercomSPIM5 = SPI{Bus: sam.SERCOM5_SPIM, SERCOM: 5}
)
// setSERCOMClockGenerator sets the GCLK for sercom
func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
switch sercom {
case 0:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 1:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 2:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 3:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 4:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 5:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
}
// This chip has five TCC peripherals, which have PWM as one feature.
var (
TCC0 = (*TCC)(sam.TCC0)
+46
View File
@@ -32,6 +32,52 @@ var (
sercomSPIM7 = SPI{Bus: sam.SERCOM7_SPIM, SERCOM: 7}
)
// setSERCOMClockGenerator sets the GCLK for sercom
func setSERCOMClockGenerator(sercom uint8, gclk uint32) {
switch sercom {
case 0:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM0_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM0_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 1:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBAMASK.SetBits(sam.MCLK_APBAMASK_SERCOM1_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM1_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 2:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM2_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM2_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 3:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBBMASK.SetBits(sam.MCLK_APBBMASK_SERCOM3_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM3_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 4:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM4_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM4_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 5:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM5_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM5_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 6:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM6_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM6_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
case 7:
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].ClearBits(sam.GCLK_PCHCTRL_CHEN)
sam.MCLK.APBDMASK.SetBits(sam.MCLK_APBDMASK_SERCOM7_)
sam.GCLK.PCHCTRL[sam.PCHCTRL_GCLK_SERCOM7_CORE].Set((gclk << sam.GCLK_PCHCTRL_GEN_Pos) |
sam.GCLK_PCHCTRL_CHEN)
}
}
// This chip has five TCC peripherals, which have PWM as one feature.
var (
TCC0 = (*TCC)(sam.TCC0)
+85
View File
@@ -5,11 +5,15 @@ package machine
import (
"device/esp"
"runtime/interrupt"
"runtime/volatile"
"sync"
"unsafe"
)
const deviceName = esp.Device
const maxPin = 22
const cpuInterruptFromPin = 6
// CPUFrequency returns the current CPU frequency of the chip.
// Currently it is a fixed frequency but it may allow changing in the future.
@@ -24,6 +28,18 @@ const (
PinInputPulldown
)
type PinChange uint8
// Pin change interrupt constants for SetInterrupt.
const (
PinNoInterrupt PinChange = iota
PinRising
PinFalling
PinToggle
PinLowLevel
PinHighLevel
)
// Configure this pin with the given configuration.
func (p Pin) Configure(config PinConfig) {
if p == NoPin {
@@ -84,6 +100,11 @@ func (p Pin) mux() *volatile.Register32 {
return (*volatile.Register32)(unsafe.Pointer((uintptr(unsafe.Pointer(&esp.IO_MUX.GPIO0)) + uintptr(p)*4)))
}
// pin returns the PIN register corresponding to the given GPIO pin.
func (p Pin) pin() *volatile.Register32 {
return (*volatile.Register32)(unsafe.Pointer((uintptr(unsafe.Pointer(&esp.GPIO.PIN0)) + uintptr(p)*4)))
}
// Set the pin to high or low.
// Warning: only use this on an output pin!
func (p Pin) Set(value bool) {
@@ -129,6 +150,70 @@ func (p Pin) portMaskClear() (*volatile.Register32, uint32) {
return &esp.GPIO.OUT_W1TC, 1 << p
}
// SetInterrupt sets an interrupt to be executed when a particular pin changes
// state. The pin should already be configured as an input, including a pull up
// or down if no external pull is provided.
//
// You can pass a nil func to unset the pin change interrupt. If you do so,
// the change parameter is ignored and can be set to any value (such as 0).
// If the pin is already configured with a callback, you must first unset
// this pins interrupt before you can set a new callback.
func (p Pin) SetInterrupt(change PinChange, callback func(Pin)) (err error) {
if p >= maxPin {
return ErrInvalidInputPin
}
if callback == nil || change == PinNoInterrupt {
// Disable this pin interrupt
p.pin().ClearBits(esp.GPIO_PIN_PIN_INT_TYPE_Msk | esp.GPIO_PIN_PIN_INT_ENA_Msk)
if pinCallbacks[p] != nil {
pinCallbacks[p] = nil
}
return nil
}
if pinCallbacks[p] != nil {
// The pin was already configured.
// To properly re-configure a pin, unset it first and set a new
// configuration.
return ErrNoPinChangeChannel
}
pinCallbacks[p] = callback
onceSetupPinInterrupt.Do(func() {
err = setupPinInterrupt()
})
if err != nil {
return err
}
p.pin().Set(
(p.pin().Get() & ^uint32(esp.GPIO_PIN_PIN_INT_TYPE_Msk|esp.GPIO_PIN_PIN_INT_ENA_Msk)) |
uint32(change)<<esp.GPIO_PIN_PIN_INT_TYPE_Pos | uint32(1)<<esp.GPIO_PIN_PIN_INT_ENA_Pos)
return nil
}
var (
pinCallbacks [maxPin]func(Pin)
onceSetupPinInterrupt sync.Once
)
func setupPinInterrupt() error {
esp.INTERRUPT_CORE0.GPIO_INTERRUPT_PRO_MAP.Set(cpuInterruptFromPin)
return interrupt.New(cpuInterruptFromPin, func(interrupt.Interrupt) {
status := esp.GPIO.STATUS.Get()
for i, mask := 0, uint32(1); i < maxPin; i, mask = i+1, mask<<1 {
if (status&mask) != 0 && pinCallbacks[i] != nil {
pinCallbacks[i](Pin(i))
}
}
// clear interrupt bit
esp.GPIO.STATUS_W1TC.SetBits(status)
}).Enable()
}
var DefaultUART = UART0
var (
-3
View File
@@ -60,9 +60,6 @@ var (
ErrNotConfigured = errors.New("device has not been configured")
)
//go:linkname gosched runtime.Gosched
func gosched()
// PutcharUART writes a byte to the UART synchronously, without using interrupts
// or calling the scheduler
func PutcharUART(u *UART, c byte) {
+13 -4
View File
@@ -3,7 +3,9 @@
package machine
import "errors"
import (
"errors"
)
var errUARTBufferEmpty = errors.New("UART buffer empty")
@@ -40,12 +42,16 @@ const (
// Read from the RX buffer.
func (uart *UART) Read(data []byte) (n int, err error) {
// check if RX buffer is empty
size := uart.Buffered()
if size == 0 {
if len(data) == 0 {
return 0, nil
}
size := uart.Buffered()
for size == 0 {
gosched()
size = uart.Buffered()
}
// Make sure we do not read more from buffer than the data slice can hold.
if len(data) < size {
size = len(data)
@@ -89,3 +95,6 @@ func (uart *UART) Buffered() int {
func (uart *UART) Receive(data byte) {
uart.Buffer.Put(data)
}
//go:linkname gosched runtime.Gosched
func gosched() int
+7 -3
View File
@@ -606,12 +606,16 @@ func newUSBSetup(data []byte) usbSetup {
// Read from the RX buffer.
func (usbcdc *USBCDC) Read(data []byte) (n int, err error) {
// check if RX buffer is empty
size := usbcdc.Buffered()
if size == 0 {
if len(data) == 0 {
return 0, nil
}
size := usbcdc.Buffered()
for size == 0 {
gosched()
size = usbcdc.Buffered()
}
// Make sure we do not read more from buffer than the data slice can hold.
if len(data) < size {
size = len(data)
+17
View File
@@ -34,6 +34,19 @@ func (p *ProcessState) Success() bool {
return false // TODO
}
// Sys returns system-dependent exit information about
// the process. Convert it to the appropriate underlying
// type, such as syscall.WaitStatus on Unix, to access its contents.
func (p *ProcessState) Sys() interface{} {
return nil // TODO
}
// ExitCode returns the exit code of the exited process, or -1
// if the process hasn't exited or was terminated by a signal.
func (p *ProcessState) ExitCode() int {
return -1 // TODO
}
type Process struct {
Pid int
}
@@ -49,3 +62,7 @@ func (p *Process) Wait() (*ProcessState, error) {
func (p *Process) Kill() error {
return ErrNotImplemented
}
func (p *Process) Signal(sig Signal) error {
return ErrNotImplemented
}
+24
View File
@@ -0,0 +1,24 @@
package exec
import "os"
// An ExitError reports an unsuccessful exit by a command.
type ExitError struct {
*os.ProcessState
// Stderr holds a subset of the standard error output from the
// Cmd.Output method if standard error was not otherwise being
// collected.
//
// If the error output is long, Stderr may contain only a prefix
// and suffix of the output, with the middle replaced with
// text about the number of omitted bytes.
//
// Stderr is provided for debugging, for inclusion in error messages.
// Users with other needs should redirect Cmd.Stderr as needed.
Stderr []byte
}
func (e *ExitError) Error() string {
return e.ProcessState.String()
}
+22
View File
@@ -0,0 +1,22 @@
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package os
//go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || windows
// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
import (
"syscall"
)
// The only signal values guaranteed to be present in the os package on all
// systems are os.Interrupt (send the process an interrupt) and os.Kill (force
// the process to exit). On Windows, sending os.Interrupt to a process with
// os.Process.Signal is not implemented; it will return an error instead of
// sending a signal.
var (
Interrupt Signal = syscall.SIGINT
Kill Signal = syscall.SIGKILL
)
+38 -1
View File
@@ -12,6 +12,7 @@ package os
import (
"errors"
"io"
"runtime"
"syscall"
)
@@ -179,9 +180,19 @@ func (f *File) SyscallConn() (syscall.RawConn, error) {
return nil, ErrNotImplemented
}
// fd is an internal interface that is used to try a type assertion in order to
// call the Fd() method of the underlying file handle if it is implemented.
type fd interface {
Fd() uintptr
}
// Fd returns the file handle referencing the open file.
func (f *File) Fd() uintptr {
panic("unimplemented: os.file.Fd()")
handle, ok := f.handle.(fd)
if ok {
return handle.Fd()
}
return 0
}
// Truncate is a stub, not yet implemented
@@ -249,3 +260,29 @@ func Getwd() (string, error) {
func TempDir() string {
return tempDir()
}
// UserHomeDir returns the current user's home directory.
//
// On Unix, including macOS, it returns the $HOME environment variable.
// On Windows, it returns %USERPROFILE%.
// On Plan 9, it returns the $home environment variable.
func UserHomeDir() (string, error) {
env, enverr := "HOME", "$HOME"
switch runtime.GOOS {
case "windows":
env, enverr = "USERPROFILE", "%userprofile%"
case "plan9":
env, enverr = "home", "$home"
}
if v := Getenv(env); v != "" {
return v, nil
}
// On some geese the home directory is not always defined.
switch runtime.GOOS {
case "android":
return "/sdcard", nil
case "ios":
return "/", nil
}
return "", errors.New(enverr + " is not defined")
}
+4 -2
View File
@@ -26,8 +26,6 @@ var (
Stderr = NewFile(uintptr(syscall.Stderr), "/dev/stderr")
)
const DevNull = "/dev/null"
// isOS indicates whether we're running on a real operating system with
// filesystem support.
const isOS = true
@@ -120,6 +118,10 @@ func (f unixFileHandle) Close() error {
return handleSyscallError(syscall.Close(syscallFd(f)))
}
func (f unixFileHandle) Fd() uintptr {
return uintptr(f)
}
// Chmod changes the mode of the named file to mode.
// If the file is a symbolic link, it changes the mode of the link's target.
// If there is an error, it will be of type *PathError.
+46
View File
@@ -4,7 +4,9 @@
package os_test
import (
"io"
. "os"
"runtime"
"testing"
)
@@ -68,3 +70,47 @@ func TestChdir(t *testing.T) {
t.Errorf("Remove %s: %s", dir, err)
}
}
func TestStandardFd(t *testing.T) {
if runtime.GOOS == "windows" {
t.Log("TODO: TestFd fails on Windows, skipping")
return
}
if fd := Stdin.Fd(); fd != 0 {
t.Errorf("Stdin.Fd() = %d, want 0", fd)
}
if fd := Stdout.Fd(); fd != 1 {
t.Errorf("Stdout.Fd() = %d, want 1", fd)
}
if fd := Stderr.Fd(); fd != 2 {
t.Errorf("Stderr.Fd() = %d, want 2", fd)
}
}
func TestFd(t *testing.T) {
if runtime.GOOS == "windows" {
t.Log("TODO: TestFd fails on Windows, skipping")
return
}
f := newFile("TestFd.txt", t)
defer Remove(f.Name())
defer f.Close()
const data = "hello, world\n"
io.WriteString(f, data)
fd := NewFile(f.Fd(), "as-fd")
defer fd.Close()
b := make([]byte, 5)
n, err := fd.ReadAt(b, 0)
if n != 5 && err != nil {
t.Errorf("Failed to read 5 bytes from file descriptor: %v", err)
}
if string(b) != data[:5] {
t.Errorf("File descriptor contents not equal to file contents.")
}
}
+34 -2
View File
@@ -15,6 +15,8 @@ var (
Stderr = NewFile(2, "/dev/stderr")
)
const DevNull = "/dev/null"
// isOS indicates whether we're running on a real operating system with
// filesystem support.
const isOS = false
@@ -36,9 +38,26 @@ func NewFile(fd uintptr, name string) *File {
return &File{&file{stdioFileHandle(fd), name}}
}
// Read is unsupported on this system.
// Read reads up to len(b) bytes from machine.Serial.
// It returns the number of bytes read and any error encountered.
func (f stdioFileHandle) Read(b []byte) (n int, err error) {
return 0, ErrUnsupported
if len(b) == 0 {
return 0, nil
}
size := buffered()
for size == 0 {
gosched()
size = buffered()
}
if size > len(b) {
size = len(b)
}
for i := 0; i < size; i++ {
b[i] = getchar()
}
return size, nil
}
func (f stdioFileHandle) ReadAt(b []byte, off int64) (n int, err error) {
@@ -69,9 +88,22 @@ func (f stdioFileHandle) Seek(offset int64, whence int) (int64, error) {
return -1, ErrUnsupported
}
func (f stdioFileHandle) Fd() uintptr {
return uintptr(f)
}
//go:linkname putchar runtime.putchar
func putchar(c byte)
//go:linkname getchar runtime.getchar
func getchar() byte
//go:linkname buffered runtime.buffered
func buffered() int
//go:linkname gosched runtime.Gosched
func gosched() int
func Pipe() (r *File, w *File, err error) {
return nil, nil, ErrNotImplemented
}
+5
View File
@@ -1,6 +1,9 @@
//go:build darwin || (linux && !baremetal)
// +build darwin linux,!baremetal
// target wasi sets GOOS=linux and thus the +linux build tag,
// even though it doesn't show up in "tinygo info target -wasi"
// Portions copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -12,6 +15,8 @@ import (
"syscall"
)
const DevNull = "/dev/null"
type syscallFd = int
// fixLongPath is a noop on non-Windows platforms.
+2
View File
@@ -13,6 +13,8 @@ import (
"unicode/utf16"
)
const DevNull = "NUL"
type syscallFd = syscall.Handle
// Symlink is a stub, it is not implemented.
+18
View File
@@ -253,3 +253,21 @@ func TestRenameFailed(t *testing.T) {
t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
}
}
func TestUserHomeDir(t *testing.T) {
dir, err := UserHomeDir()
if dir == "" && err == nil {
t.Fatal("UserHomeDir returned an empty string but no error")
}
if err != nil {
t.Logf("UserHomeDir failed: %v", err)
return
}
fi, err := Stat(dir)
if err != nil {
t.Fatal(err)
}
if !fi.IsDir() {
t.Fatalf("dir %s is not directory; type = %v", dir, fi.Mode())
}
}
+17 -12
View File
@@ -18,7 +18,7 @@ import (
// if set) and xxx contains the type kind number:
// 0 (0001): Chan
// 1 (0011): Interface
// 2 (0101): Ptr
// 2 (0101): Pointer
// 3 (0111): Slice
// 4 (1001): Array
// 5 (1011): Func
@@ -54,7 +54,7 @@ const (
UnsafePointer
Chan
Interface
Ptr
Pointer
Slice
Array
Func
@@ -62,6 +62,9 @@ const (
Struct
)
// Ptr is the old name for the Pointer kind.
const Ptr = Pointer
func (k Kind) String() string {
switch k {
case Bool:
@@ -104,7 +107,7 @@ func (k Kind) String() string {
return "chan"
case Interface:
return "interface"
case Ptr:
case Pointer:
return "ptr"
case Slice:
return "slice"
@@ -252,7 +255,7 @@ type Type interface {
// Chan: ChanDir, Elem
// Func: In, NumIn, Out, NumOut, IsVariadic.
// Map: Key, Elem
// Ptr: Elem
// Pointer: Elem
// Slice: Elem
// Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField
@@ -280,7 +283,7 @@ type Type interface {
IsVariadic() bool
// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
// It panics if the type's Kind is not Array, Chan, Map, Pointer, or Slice.
Elem() Type
// Field returns a struct type's i'th field.
@@ -350,13 +353,15 @@ func TypeOf(i interface{}) Type {
return ValueOf(i).typecode
}
func PtrTo(t Type) Type {
if t.Kind() == Ptr {
func PtrTo(t Type) Type { return PointerTo(t) }
func PointerTo(t Type) Type {
if t.Kind() == Pointer {
panic("reflect: cannot make **T type")
}
ptrType := t.(rawType)<<5 | 5 // 0b0101 == 5
if ptrType>>5 != t {
panic("reflect: PtrTo type does not fit")
panic("reflect: PointerTo type does not fit")
}
return ptrType
}
@@ -382,7 +387,7 @@ func (t rawType) Elem() Type {
func (t rawType) elem() rawType {
switch t.Kind() {
case Chan, Ptr, Slice:
case Chan, Pointer, Slice:
return t.stripPrefix()
case Array:
index := t.stripPrefix()
@@ -566,7 +571,7 @@ func (t rawType) Size() uintptr {
return 16
case String:
return unsafe.Sizeof("")
case UnsafePointer, Chan, Map, Ptr:
case UnsafePointer, Chan, Map, Pointer:
return unsafe.Sizeof(uintptr(0))
case Slice:
return unsafe.Sizeof([]int{})
@@ -615,7 +620,7 @@ func (t rawType) Align() int {
return int(unsafe.Alignof(complex128(0)))
case String:
return int(unsafe.Alignof(""))
case UnsafePointer, Chan, Map, Ptr:
case UnsafePointer, Chan, Map, Pointer:
return int(unsafe.Alignof(uintptr(0)))
case Slice:
return int(unsafe.Alignof([]int(nil)))
@@ -681,7 +686,7 @@ func (t rawType) Comparable() bool {
return true
case Interface:
return true
case Ptr:
case Pointer:
return true
case Slice:
return false
+5
View File
@@ -861,6 +861,11 @@ func (v Value) FieldByIndex(index []int) Value {
panic("unimplemented: (reflect.Value).FieldByIndex()")
}
// FieldByIndexErr returns the nested field corresponding to index.
func (v Value) FieldByIndexErr(index []int) (Value, error) {
return Value{}, &ValueError{Method: "FieldByIndexErr"}
}
func (v Value) FieldByName(name string) Value {
panic("unimplemented: (reflect.Value).FieldByName()")
}
+56
View File
@@ -0,0 +1,56 @@
package runtime
// This file implements various core algorithms used in the runtime package and
// standard library.
import "unsafe"
// This function is used by hash/maphash.
func fastrand() uint32 {
xorshift32State = xorshift32(xorshift32State)
return xorshift32State
}
var xorshift32State uint32 = 1
func xorshift32(x uint32) uint32 {
// Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs".
// Improved sequence based on
// http://www.iro.umontreal.ca/~lecuyer/myftp/papers/xorshift.pdf
x ^= x << 7
x ^= x >> 1
x ^= x << 9
return x
}
// This function is used by hash/maphash.
func memhash(p unsafe.Pointer, seed, s uintptr) uintptr {
if unsafe.Sizeof(uintptr(0)) > 4 {
return seed ^ uintptr(hash64(p, s))
}
return seed ^ uintptr(hash32(p, s))
}
// Get FNV-1a hash of the given memory buffer.
//
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash
func hash32(ptr unsafe.Pointer, n uintptr) uint32 {
var result uint32 = 2166136261 // FNV offset basis
for i := uintptr(0); i < n; i++ {
c := *(*uint8)(unsafe.Pointer(uintptr(ptr) + i))
result ^= uint32(c) // XOR with byte
result *= 16777619 // FNV prime
}
return result
}
// Also a FNV-1a hash.
func hash64(ptr unsafe.Pointer, n uintptr) uint64 {
var result uint64 = 14695981039346656037 // FNV offset basis
for i := uintptr(0); i < n; i++ {
c := *(*uint8)(unsafe.Pointer(uintptr(ptr) + i))
result ^= uint64(c) // XOR with byte
result *= 1099511628211 // FNV prime
}
return result
}
+20
View File
@@ -0,0 +1,20 @@
package runtime
// NumCPU returns the number of logical CPUs usable by the current process.
//
// The set of available CPUs is checked by querying the operating system
// at process startup. Changes to operating system CPU allocation after
// process startup are not reflected.
func NumCPU() int {
return 1
}
// Stub for NumCgoCall, does not return the real value
func NumCgoCall() int {
return 0
}
// Stub for NumGoroutine, does not return the real value
func NumGoroutine() int {
return 1
}
+25
View File
@@ -15,3 +15,28 @@ func SetMaxStack(n int) int {
func Stack() []byte {
return nil
}
// ReadBuildInfo returns the build information embedded
// in the running binary. The information is available only
// in binaries built with module support.
//
// Not implemented.
func ReadBuildInfo() (info *BuildInfo, ok bool) {
return nil, false
}
// BuildInfo represents the build information read from
// the running binary.
type BuildInfo struct {
Path string // The main package path
Main Module // The module containing the main package
Deps []*Module // Module dependencies
}
// Module represents a module.
type Module struct {
Path string // module path
Version string // module version
Sum string // checksum
Replace *Module // replaced by this module
}
+12
View File
@@ -3,3 +3,15 @@ package runtime
func Callers(skip int, pc []uintptr) int {
return 0
}
// buildVersion is the Tinygo tree's version string at build time.
//
// This is set by the linker.
var buildVersion string
// Version returns the Tinygo tree's version string.
// It is the same as goenv.Version, or in case of a development build,
// it will be the concatenation of goenv.Version and the git commit hash.
func Version() string {
return buildVersion
}
+3 -5
View File
@@ -32,11 +32,9 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
// Failed to make the heap bigger, so we must really be out of memory.
runtimePanic("out of memory")
}
for i := uintptr(0); i < uintptr(size); i += 4 {
ptr := (*uint32)(unsafe.Pointer(addr + i))
*ptr = 0
}
return unsafe.Pointer(addr)
pointer := unsafe.Pointer(addr)
memzero(pointer, size)
return pointer
}
func realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer {
+9 -22
View File
@@ -37,19 +37,6 @@ type hashmapIterator struct {
bucketIndex uint8
}
// Get FNV-1a hash of this key.
//
// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash
func hashmapHash(ptr unsafe.Pointer, n uintptr) uint32 {
var result uint32 = 2166136261 // FNV offset basis
for i := uintptr(0); i < n; i++ {
c := *(*uint8)(unsafe.Pointer(uintptr(ptr) + i))
result ^= uint32(c) // XOR with byte
result *= 16777619 // FNV prime
}
return result
}
// Get the topmost 8 bits of the hash, without using a special value (like 0).
func hashmapTopHash(hash uint32) uint8 {
tophash := uint8(hash >> 24)
@@ -308,7 +295,7 @@ func hashmapNext(m *hashmap, it *hashmapIterator, key, value unsafe.Pointer) boo
func hashmapBinarySet(m *hashmap, key, value unsafe.Pointer) {
// TODO: detect nil map here and throw a better panic message?
hash := hashmapHash(key, uintptr(m.keySize))
hash := hash32(key, uintptr(m.keySize))
hashmapSet(m, key, value, hash, memequal)
}
@@ -317,7 +304,7 @@ func hashmapBinaryGet(m *hashmap, key, value unsafe.Pointer, valueSize uintptr)
memzero(value, uintptr(valueSize))
return false
}
hash := hashmapHash(key, uintptr(m.keySize))
hash := hash32(key, uintptr(m.keySize))
return hashmapGet(m, key, value, valueSize, hash, memequal)
}
@@ -325,7 +312,7 @@ func hashmapBinaryDelete(m *hashmap, key unsafe.Pointer) {
if m == nil {
return
}
hash := hashmapHash(key, uintptr(m.keySize))
hash := hash32(key, uintptr(m.keySize))
hashmapDelete(m, key, hash, memequal)
}
@@ -337,7 +324,7 @@ func hashmapStringEqual(x, y unsafe.Pointer, n uintptr) bool {
func hashmapStringHash(s string) uint32 {
_s := (*_string)(unsafe.Pointer(&s))
return hashmapHash(unsafe.Pointer(_s.ptr), uintptr(_s.length))
return hash32(unsafe.Pointer(_s.ptr), uintptr(_s.length))
}
func hashmapStringSet(m *hashmap, key string, value unsafe.Pointer) {
@@ -370,7 +357,7 @@ func hashmapFloat32Hash(ptr unsafe.Pointer) uint32 {
// convert -0 to 0 for hashing
f = 0
}
return hashmapHash(unsafe.Pointer(&f), 4)
return hash32(unsafe.Pointer(&f), 4)
}
func hashmapFloat64Hash(ptr unsafe.Pointer) uint32 {
@@ -379,7 +366,7 @@ func hashmapFloat64Hash(ptr unsafe.Pointer) uint32 {
// convert -0 to 0 for hashing
f = 0
}
return hashmapHash(unsafe.Pointer(&f), 8)
return hash32(unsafe.Pointer(&f), 8)
}
func hashmapInterfaceHash(itf interface{}) uint32 {
@@ -397,9 +384,9 @@ func hashmapInterfaceHash(itf interface{}) uint32 {
switch x.RawType().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return hashmapHash(ptr, x.RawType().Size())
return hash32(ptr, x.RawType().Size())
case reflect.Bool, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return hashmapHash(ptr, x.RawType().Size())
return hash32(ptr, x.RawType().Size())
case reflect.Float32:
// It should be possible to just has the contents. However, NaN != NaN
// so if you're using lots of NaNs as map keys (you shouldn't) then hash
@@ -421,7 +408,7 @@ func hashmapInterfaceHash(itf interface{}) uint32 {
// It might seem better to just return the pointer, but that won't
// result in an evenly distributed hashmap. Instead, hash the pointer
// like most other types.
return hashmapHash(ptr, x.RawType().Size())
return hash32(ptr, x.RawType().Size())
case reflect.Array:
var hash uint32
for i := 0; i < x.Len(); i++ {
+140 -14
View File
@@ -34,9 +34,9 @@ func (i Interrupt) Enable() error {
// Set pulse interrupt type (rising edge detection)
esp.INTERRUPT_CORE0.CPU_INT_TYPE.SetBits(1 << i.num)
// Set default threshold to 5
// Set default threshold to defaultThreshold
reg := (*volatile.Register32)(unsafe.Pointer((uintptr(unsafe.Pointer(&esp.INTERRUPT_CORE0.CPU_INT_PRI_0)) + uintptr(i.num)*4)))
reg.Set(5)
reg.Set(defaultThreshold)
// Reset interrupt before reenabling
esp.INTERRUPT_CORE0.CPU_INT_CLEAR.SetBits(1 << i.num)
@@ -47,6 +47,118 @@ func (i Interrupt) Enable() error {
return nil
}
// Adding pseudo function calls that is replaced by the compiler with the actual
// functions registered through interrupt.New.
//go:linkname callHandlers runtime/interrupt.callHandlers
func callHandlers(num int)
const (
IRQNUM_1 = 1 + iota
IRQNUM_2
IRQNUM_3
IRQNUM_4
IRQNUM_5
IRQNUM_6
IRQNUM_7
IRQNUM_8
IRQNUM_9
IRQNUM_10
IRQNUM_11
IRQNUM_12
IRQNUM_13
IRQNUM_14
IRQNUM_15
IRQNUM_16
IRQNUM_17
IRQNUM_18
IRQNUM_19
IRQNUM_20
IRQNUM_21
IRQNUM_22
IRQNUM_23
IRQNUM_24
IRQNUM_25
IRQNUM_26
IRQNUM_27
IRQNUM_28
IRQNUM_29
IRQNUM_30
IRQNUM_31
)
const (
defaultThreshold = 5
disableThreshold = 10
)
//go:inline
func callHandler(n int) {
switch n {
case IRQNUM_1:
callHandlers(IRQNUM_1)
case IRQNUM_2:
callHandlers(IRQNUM_2)
case IRQNUM_3:
callHandlers(IRQNUM_3)
case IRQNUM_4:
callHandlers(IRQNUM_4)
case IRQNUM_5:
callHandlers(IRQNUM_5)
case IRQNUM_6:
callHandlers(IRQNUM_6)
case IRQNUM_7:
callHandlers(IRQNUM_7)
case IRQNUM_8:
callHandlers(IRQNUM_8)
case IRQNUM_9:
callHandlers(IRQNUM_9)
case IRQNUM_10:
callHandlers(IRQNUM_10)
case IRQNUM_11:
callHandlers(IRQNUM_11)
case IRQNUM_12:
callHandlers(IRQNUM_12)
case IRQNUM_13:
callHandlers(IRQNUM_13)
case IRQNUM_14:
callHandlers(IRQNUM_14)
case IRQNUM_15:
callHandlers(IRQNUM_15)
case IRQNUM_16:
callHandlers(IRQNUM_16)
case IRQNUM_17:
callHandlers(IRQNUM_17)
case IRQNUM_18:
callHandlers(IRQNUM_18)
case IRQNUM_19:
callHandlers(IRQNUM_19)
case IRQNUM_20:
callHandlers(IRQNUM_20)
case IRQNUM_21:
callHandlers(IRQNUM_21)
case IRQNUM_22:
callHandlers(IRQNUM_22)
case IRQNUM_23:
callHandlers(IRQNUM_23)
case IRQNUM_24:
callHandlers(IRQNUM_24)
case IRQNUM_25:
callHandlers(IRQNUM_25)
case IRQNUM_26:
callHandlers(IRQNUM_26)
case IRQNUM_27:
callHandlers(IRQNUM_27)
case IRQNUM_28:
callHandlers(IRQNUM_28)
case IRQNUM_29:
callHandlers(IRQNUM_29)
case IRQNUM_30:
callHandlers(IRQNUM_30)
case IRQNUM_31:
callHandlers(IRQNUM_31)
}
}
//export handleInterrupt
func handleInterrupt() {
mcause := riscv.MCAUSE.Get()
@@ -54,12 +166,17 @@ func handleInterrupt() {
interruptNumber := uint32(mcause & 0x1f)
if !exception && interruptNumber > 0 {
// save mepc, which could be overwritten by another CPU interrupt
// save MSTATUS & MEPC, which could be overwritten by another CPU interrupt
mstatus := riscv.MSTATUS.Get()
mepc := riscv.MEPC.Get()
// Useing threshold to temporary disable this interrupts.
// FYI: using CPU interrupt enable bit make runtime to loose interrupts.
reg := (*volatile.Register32)(unsafe.Pointer((uintptr(unsafe.Pointer(&esp.INTERRUPT_CORE0.CPU_INT_PRI_0)) + uintptr(interruptNumber)*4)))
thresholdSave := reg.Get()
reg.Set(disableThreshold)
riscv.Asm("fence")
// disable interrupt
interruptBit := uint32(1 << interruptNumber)
esp.INTERRUPT_CORE0.CPU_INT_ENABLE.ClearBits(interruptBit)
// reset pending status interrupt
if esp.INTERRUPT_CORE0.CPU_INT_TYPE.Get()&interruptBit != 0 {
@@ -72,23 +189,22 @@ func handleInterrupt() {
}
// enable CPU interrupts
riscv.MSTATUS.SetBits(0x8)
riscv.MSTATUS.SetBits(1 << 3)
// Call registered interrupt handler(s)
esp.HandleInterrupt(int(interruptNumber))
callHandler(int(interruptNumber))
// disable CPU interrupts
riscv.MSTATUS.ClearBits(0x8)
riscv.MSTATUS.ClearBits(1 << 3)
// mpie must be set to 1 to resume interrupts after 'MRET'
riscv.MSTATUS.SetBits(0x80)
// restore interrupt threshold to enable interrupt again
reg.Set(thresholdSave)
riscv.Asm("fence")
// restore MEPC
// restore MSTATUS & MEPC
riscv.MSTATUS.Set(mstatus)
riscv.MEPC.Set(mepc)
// enable this interrupt
esp.INTERRUPT_CORE0.CPU_INT_ENABLE.SetBits(interruptBit)
// do not enable CPU interrupts now
// the 'MRET' in src/device/riscv/handleinterrupt.S will copies the state of MPIE back into MIE, and subsequently clears MPIE.
// riscv.MSTATUS.SetBits(0x8)
@@ -104,6 +220,16 @@ func handleException(mcause uintptr) {
println("*** Exception: pc:", riscv.MEPC.Get())
println("*** Exception: code:", uint32(mcause&0x1f))
println("*** Exception: mcause:", mcause)
switch uint32(mcause & 0x1f) {
case 1:
println("*** virtual addess:", riscv.MTVAL.Get())
case 2:
println("*** opcode:", riscv.MTVAL.Get())
case 5:
println("*** read address:", riscv.MTVAL.Get())
case 7:
println("*** write address:", riscv.MTVAL.Get())
}
for {
riscv.Asm("wfi")
}
+10
View File
@@ -14,6 +14,16 @@ func putchar(c byte) {
// dummy, TODO
}
func getchar() byte {
// dummy, TODO
return 0
}
func buffered() int {
// dummy, TODO
return 0
}
//go:extern _sbss
var _sbss [0]byte
+12
View File
@@ -16,6 +16,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
// Sleep for a given period. The period is defined by the WDT peripheral, and is
// on most chips (at least) 3 bits wide, in powers of two from 16ms to 2s
// (0=16ms, 1=32ms, 2=64ms...). Note that the WDT is not very accurate: it can
+15
View File
@@ -30,12 +30,27 @@ func init() {
// connect to USB CDC interface
machine.Serial.Configure(machine.UARTConfig{})
if !machine.USB.Configured() {
machine.USB.Configure(machine.UARTConfig{})
}
}
func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
func initClocks() {
// Set 1 Flash Wait State for 48MHz, required for 3.3V operation according to SAMD21 Datasheet
sam.NVMCTRL.CTRLB.SetBits(sam.NVMCTRL_CTRLB_RWS_HALF << sam.NVMCTRL_CTRLB_RWS_Pos)
+15
View File
@@ -30,12 +30,27 @@ func init() {
// connect to USB CDC interface
machine.Serial.Configure(machine.UARTConfig{})
if !machine.USB.Configured() {
machine.USB.Configure(machine.UARTConfig{})
}
}
func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
func initClocks() {
// set flash wait state
sam.NVMCTRL.CTRLA.SetBits(0 << sam.NVMCTRL_CTRLA_RWS_Pos)
+10
View File
@@ -14,6 +14,16 @@ func putchar(c byte) {
// UART is not supported.
}
func getchar() byte {
// UART is not supported.
return 0
}
func buffered() int {
// UART is not supported.
return 0
}
func sleepWDT(period uint8) {
// TODO: use the watchdog timer instead of a busy loop.
for i := 0x45; i != 0; i-- {
+10
View File
@@ -49,6 +49,16 @@ func putchar(c byte) {
stdoutWrite.Set(uint8(c))
}
func getchar() byte {
// dummy, TODO
return 0
}
func buffered() int {
// dummy, TODO
return 0
}
func waitForEvents() {
arm.Asm("wfe")
}
+12
View File
@@ -15,6 +15,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
// Initialize .bss: zero-initialized global variables.
// The .data section has already been loaded by the ROM bootloader.
func clearbss() {
+12
View File
@@ -18,6 +18,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
// Write to the internal control bus (using I2C?).
// Signature found here:
// https://github.com/espressif/ESP8266_RTOS_SDK/blob/14171de0/components/esp8266/include/esp8266/rom_functions.h#L54
+12
View File
@@ -99,6 +99,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
var timerWakeup volatile.Register8
func ticks() timeUnit {
+12
View File
@@ -111,6 +111,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
var timerWakeup volatile.Register8
func ticks() timeUnit {
+12
View File
@@ -126,6 +126,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.UART1.Buffered() == 0 {
Gosched()
}
v, _ := machine.UART1.ReadByte()
return v
}
func buffered() int {
return machine.UART1.Buffered()
}
func exit(code int) {
abort()
}
+12
View File
@@ -66,6 +66,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
func sleepTicks(d timeUnit) {
for d != 0 {
ticks := uint32(d) & 0x7fffff // 23 bits (to be on the safe side)
+10
View File
@@ -231,6 +231,16 @@ func putchar(c byte) {
machine.PutcharUART(machine.UART0, c)
}
func getchar() byte {
// dummy, TODO
return 0
}
func buffered() int {
// dummy, TODO
return 0
}
func exit(code int) {
abort()
}
+12
View File
@@ -45,6 +45,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
// machineInit is provided by package machine.
func machineInit()
+12
View File
@@ -20,6 +20,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
// initCLK sets clock to 72MHz using HSE 8MHz crystal w/ PLL X 9 (8MHz x 9 = 72MHz).
func initCLK() {
stm32.FLASH.ACR.SetBits(stm32.FLASH_ACR_LATENCY_WS2) // Two wait states, per datasheet
+12
View File
@@ -21,6 +21,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
func initCLK() {
// Reset clock registers
// Set HSION
+12
View File
@@ -163,3 +163,15 @@ func initCOM() {
func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
+12
View File
@@ -38,6 +38,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
func initCLK() {
// PWR_CLK_ENABLE
stm32.RCC.APB1ENR.SetBits(stm32.RCC_APB1ENR_PWREN)
+12
View File
@@ -16,6 +16,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
func initCLK() {
// Set Power Regulator to enable max performance (1.8V)
stm32.PWR.CR.ReplaceBits(1<<stm32.PWR_CR_VOS_Pos, stm32.PWR_CR_VOS_Msk, 0)
+12
View File
@@ -47,6 +47,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
func initCLK() {
// PWR_CLK_ENABLE
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_PWREN)
+12
View File
@@ -39,6 +39,18 @@ func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
func initCLK() {
// PWR_CLK_ENABLE
+12
View File
@@ -102,3 +102,15 @@ func initCLK() {
func putchar(c byte) {
machine.Serial.WriteByte(c)
}
func getchar() byte {
for machine.Serial.Buffered() == 0 {
Gosched()
}
v, _ := machine.Serial.ReadByte()
return v
}
func buffered() int {
return machine.Serial.Buffered()
}
+10
View File
@@ -55,6 +55,16 @@ func putchar(c byte) {
stdoutWrite.Set(uint8(c))
}
func getchar() byte {
// dummy, TODO
return 0
}
func buffered() int {
// dummy, TODO
return 0
}
func abort() {
exit(1)
}
+23
View File
@@ -0,0 +1,23 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build darwin || linux
// +build darwin linux
package syscall_test
import (
"syscall"
"testing"
)
func TestMmap(t *testing.T) {
b, err := syscall.Mmap(-1, 0, syscall.Getpagesize(), syscall.PROT_NONE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
if err != nil {
t.Fatalf("Mmap: %v", err)
}
if err := syscall.Munmap(b); err != nil {
t.Fatalf("Munmap: %v", err)
}
}
+28
View File
@@ -226,6 +226,14 @@ func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, e
return (*[1 << 30]byte)(addr)[:length:length], nil
}
func Munmap(b []byte) (err error) {
errCode := libc_munmap(unsafe.Pointer(&b[0]), uintptr(len(b)))
if errCode != 0 {
err = getErrno()
}
return err
}
func Mprotect(b []byte, prot int) (err error) {
errCode := libc_mprotect(unsafe.Pointer(&b[0]), uintptr(len(b)), int32(prot))
if errCode != 0 {
@@ -234,7 +242,19 @@ func Mprotect(b []byte, prot int) (err error) {
return
}
func Getpagesize() int {
return int(libc_getpagesize())
}
func Environ() []string {
// This function combines all the environment into a single allocation.
// While this optimizes for memory usage and garbage collector
// overhead, it does run the risk of potentially pinning a "large"
// allocation if a user holds onto a single environment variable or
// value. Having each variable be its own allocation would make the
// trade-off in the other direction.
// calculate total memory required
var length uintptr
var vars int
@@ -335,10 +355,18 @@ func libc_dup(fd int32) int32
//export mmap
func libc_mmap(addr unsafe.Pointer, length uintptr, prot, flags, fd int32, offset uintptr) unsafe.Pointer
// int munmap(void *addr, size_t length);
//export munmap
func libc_munmap(addr unsafe.Pointer, length uintptr) int32
// int mprotect(void *addr, size_t len, int prot);
//export mprotect
func libc_mprotect(addr unsafe.Pointer, len uintptr, prot int32) int32
// int getpagesize();
//export getpagesize
func libc_getpagesize() int32
// int chdir(const char *pathname, mode_t mode);
//export chdir
func libc_chdir(pathname *byte) int32
+15
View File
@@ -4,6 +4,7 @@
package syscall
import (
"internal/itoa"
"unsafe"
)
@@ -82,6 +83,20 @@ const (
SIGTERM Signal = 0xf
)
func (s Signal) Signal() {}
func (s Signal) String() string {
if 0 <= s && int(s) < len(signals) {
str := signals[s]
if str != "" {
return str
}
}
return "signal " + itoa.Itoa(int(s))
}
var signals = [...]string{}
const (
Stdin = 0
Stdout = 1
@@ -3,6 +3,10 @@
package syscall
import (
"internal/itoa"
)
// A Signal is a number describing a process signal.
// It implements the os.Signal interface.
type Signal int
@@ -17,6 +21,20 @@ const (
SIGTERM
)
func (s Signal) Signal() {}
func (s Signal) String() string {
if 0 <= s && int(s) < len(signals) {
str := signals[s]
if str != "" {
return str
}
}
return "signal " + itoa.Itoa(int(s))
}
var signals = [...]string{}
// File system
const (
+34 -6
View File
@@ -4,6 +4,7 @@
package syscall
import (
"internal/itoa"
"unsafe"
)
@@ -12,14 +13,28 @@ import (
type Signal int
const (
SIGCHLD = 16
SIGINT = 2
SIGKILL = 9
SIGTRAP = 5
SIGQUIT = 3
SIGTERM = 15
SIGCHLD Signal = 16
SIGINT Signal = 2
SIGKILL Signal = 9
SIGTRAP Signal = 5
SIGQUIT Signal = 3
SIGTERM Signal = 15
)
func (s Signal) Signal() {}
func (s Signal) String() string {
if 0 <= s && int(s) < len(signals) {
str := signals[s]
if str != "" {
return str
}
}
return "signal " + itoa.Itoa(int(s))
}
var signals = [...]string{}
const (
Stdin = 0
Stdout = 1
@@ -44,6 +59,19 @@ const (
O_SYNC = __WASI_FDFLAGS_SYNC
O_CLOEXEC = 0
// ../../lib/wasi-libc/sysroot/include/sys/mman.h
MAP_FILE = 0
MAP_SHARED = 0x01
MAP_PRIVATE = 0x02
MAP_ANON = 0x20
MAP_ANONYMOUS = MAP_ANON
// ../../lib/wasi-libc/sysroot/include/sys/mman.h
PROT_NONE = 0
PROT_READ = 1
PROT_WRITE = 2
PROT_EXEC = 4
)
//go:extern errno
+48
View File
@@ -3,6 +3,10 @@
package syscall
import (
"internal/itoa"
)
// Most code here has been copied from the Go sources:
// https://github.com/golang/go/blob/go1.12/src/syscall/syscall_js.go
// It has the following copyright note:
@@ -23,8 +27,28 @@ const (
SIGTRAP
SIGQUIT
SIGTERM
SIGILL
SIGABRT
SIGBUS
SIGFPE
SIGSEGV
SIGPIPE
)
func (s Signal) Signal() {}
func (s Signal) String() string {
if 0 <= s && int(s) < len(signals) {
str := signals[s]
if str != "" {
return str
}
}
return "signal " + itoa.Itoa(int(s))
}
var signals = [...]string{}
// File system
const (
@@ -48,6 +72,22 @@ const (
O_CLOEXEC = 0
)
// Dummy values to allow compiling tests
// Dummy source: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/sys/mman.h.auto.html
const (
PROT_NONE = 0x00 // no permissions
PROT_READ = 0x01 // pages can be read
PROT_WRITE = 0x02 // pages can be written
PROT_EXEC = 0x04 // pages can be executed
MAP_SHARED = 0x0001 // share changes
MAP_PRIVATE = 0x0002 // changes are private
MAP_FILE = 0x0000 // map from file (default)
MAP_ANON = 0x1000 // allocated from memory, swap space
MAP_ANONYMOUS = MAP_ANON
)
func runtime_envs() []string
func Getenv(key string) (value string, found bool) {
@@ -150,6 +190,14 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int,
return 0, ENOSYS
}
func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
return nil, ENOSYS
}
func Munmap(b []byte) (err error) {
return ENOSYS
}
type Timeval struct {
Sec int64
Usec int64
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
//go:build baremetal
// +build baremetal
package testing
const isBaremetal = true
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//
//go:build !baremetal
// +build !baremetal
package testing
const isBaremetal = false
+16
View File
@@ -26,6 +26,11 @@ type matcher struct {
var matchMutex sync.Mutex
func newMatcher(matchString func(pat, str string) (bool, error), patterns, name string) *matcher {
if isBaremetal {
// Probably not enough ram to load regexp, substitute something simpler.
matchString = fakeMatchString
}
var filter []string
if patterns != "" {
filter = splitRegexp(patterns)
@@ -166,3 +171,14 @@ func isSpace(r rune) bool {
}
return false
}
// A fake regexp matcher.
// Inflexible, but saves 50KB of flash and 50KB of RAM per -size full,
// and lets tests pass on cortex-m.
func fakeMatchString(pat, str string) (bool, error) {
if pat == ".*" {
return true, nil
}
matched := strings.Contains(str, pat)
return matched, nil
}
+32 -1
View File
@@ -205,6 +205,10 @@ func (fi *frameInfo) exec(bytecode []byte) ([]frameInfoLine, error) {
if err != nil {
return nil, err
}
case 3: // DW_CFA_restore
// Restore a register. Used after an outlined function call.
// It should be possible to ignore this.
// TODO: check that this is not the stack pointer.
case 0:
switch lowBits {
case 0: // DW_CFA_nop
@@ -218,7 +222,22 @@ func (fi *frameInfo) exec(bytecode []byte) ([]frameInfoLine, error) {
}
fi.loc += uint64(offset) * fi.cie.codeAlignmentFactor
entries = append(entries, fi.newLine())
// TODO: DW_CFA_advance_loc2 etc
case 0x03: // DW_CFA_advance_loc2
var offset uint16
err := binary.Read(r, binary.LittleEndian, &offset)
if err != nil {
return nil, err
}
fi.loc += uint64(offset) * fi.cie.codeAlignmentFactor
entries = append(entries, fi.newLine())
case 0x04: // DW_CFA_advance_loc4
var offset uint32
err := binary.Read(r, binary.LittleEndian, &offset)
if err != nil {
return nil, err
}
fi.loc += uint64(offset) * fi.cie.codeAlignmentFactor
entries = append(entries, fi.newLine())
case 0x05: // DW_CFA_offset_extended
// Semantics are the same as DW_CFA_offset, but the encoding is
// different. Ignore it just like DW_CFA_offset.
@@ -239,6 +258,18 @@ func (fi *frameInfo) exec(bytecode []byte) ([]frameInfoLine, error) {
if err != nil {
return nil, err
}
case 0x09: // DW_CFA_register
// Copies a register. Emitted by the machine outliner, for example.
// It should be possible to ignore this.
// TODO: check that the stack pointer is not affected.
_, err := readULEB128(r)
if err != nil {
return nil, err
}
_, err = readULEB128(r)
if err != nil {
return nil, err
}
case 0x0c: // DW_CFA_def_cfa
register, err := readULEB128(r)
if err != nil {
+5
View File
@@ -0,0 +1,5 @@
{
"inherits": ["esp32c3"],
"build-tags": ["esp32c312f", "esp32c3", "esp"]
}
-1
View File
@@ -11,7 +11,6 @@
"ldflags": [
"--allow-undefined",
"--stack-first",
"--export-dynamic",
"--no-demangle"
],
"emulator": ["wasmtime"],
+2 -2
View File
@@ -424,7 +424,7 @@
const dst = loadSlice(dest_addr, dest_len);
const src = loadValue(source_addr);
if (!(src instanceof Uint8Array)) {
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
mem().setUint8(returned_status_addr, 0); // Return "not ok" status
return;
}
@@ -443,7 +443,7 @@
const dst = loadValue(dest_addr);
const src = loadSlice(source_addr, source_len);
if (!(dst instanceof Uint8Array)) {
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
mem().setUint8(returned_status_addr, 0); // Return "not ok" status
return;
}
+13
View File
@@ -170,6 +170,19 @@ func main() {
assertSize(reflect.TypeOf(new(int)).Size() == unsafe.Sizeof(new(int)), "*int")
assertSize(reflect.TypeOf(zeroFunc).Size() == unsafe.Sizeof(zeroFunc), "func()")
// Test that offset is correctly calculated.
// This doesn't just test reflect but also (indirectly) that unsafe.Alignof
// works correctly.
s := struct {
small1 byte
big1 int64
small2 byte
big2 int64
}{}
st := reflect.TypeOf(s)
println("offset for int64 matches:", st.Field(1).Offset-st.Field(0).Offset == uintptr(unsafe.Pointer(&s.big1))-uintptr(unsafe.Pointer(&s.small1)))
println("offset for complex128 matches:", st.Field(3).Offset-st.Field(2).Offset == uintptr(unsafe.Pointer(&s.big2))-uintptr(unsafe.Pointer(&s.small2)))
// SetBool
rv := reflect.ValueOf(new(bool)).Elem()
rv.SetBool(true)
+2
View File
@@ -401,6 +401,8 @@ float32 4 32
float64 8 64
complex64 8 64
complex128 16 128
offset for int64 matches: true
offset for complex128 matches: true
type assertion succeeded for unreferenced type
struct tags
+9 -9
View File
@@ -6,6 +6,7 @@ import (
"errors"
"flag"
"io"
"strings"
"testing"
)
@@ -32,7 +33,7 @@ func TestAllLowercase(t *testing.T) {
"alpha",
"BETA",
"gamma",
"DELTA",
"BELTA",
}
for _, name := range names {
@@ -56,23 +57,22 @@ var benchmarks = []testing.InternalBenchmark{}
var examples = []testing.InternalExample{}
// A fake regexp matcher that can only handle two patterns.
// A fake regexp matcher.
// Inflexible, but saves 50KB of flash and 50KB of RAM per -size full,
// and lets tests pass on cortex-m3.
// and lets tests pass on cortex-m.
// Must match the one in src/testing/match.go that is substituted on bare-metal platforms,
// or "make test" will fail there.
func fakeMatchString(pat, str string) (bool, error) {
if pat == ".*" {
return true, nil
}
if pat == "[BD]" {
return (str[0] == 'B' || str[0] == 'D'), nil
}
println("BUG: fakeMatchString does not grok", pat)
return false, nil
matched := strings.Contains(str, pat)
return matched, nil
}
func main() {
testing.Init()
flag.Set("test.run", ".*/[BD]")
flag.Set("test.run", ".*/B")
m := testing.MainStart(matchStringOnly(fakeMatchString /*regexp.MatchString*/), tests, benchmarks, examples)
exitcode := m.Run()
+2 -2
View File
@@ -15,7 +15,7 @@
--- FAIL: TestAllLowercase (0.00s)
--- FAIL: TestAllLowercase/BETA (0.00s)
expected lowercase name, got BETA
--- FAIL: TestAllLowercase/DELTA (0.00s)
expected lowercase name, got DELTA
--- FAIL: TestAllLowercase/BELTA (0.00s)
expected lowercase name, got BELTA
FAIL
exitcode: 1
+1
View File
@@ -151,6 +151,7 @@ func Optimize(mod llvm.Module, config *compileopts.Config, optLevel, sizeLevel i
funcPasses.FinalizeFunc()
// Run module passes.
// TODO: somehow set the PrepareForThinLTO flag in the pass manager builder.
modPasses := llvm.NewPassManager()
defer modPasses.Dispose()
builder.Populate(modPasses)
+25 -1
View File
@@ -11,8 +11,9 @@ import (
// modified after linking.
func CreateStackSizeLoads(mod llvm.Module, config *compileopts.Config) []string {
functionMap := map[llvm.Value][]llvm.Value{}
var functions []llvm.Value
var functions []llvm.Value // ptrtoint values of functions
var functionNames []string
var functionValues []llvm.Value // direct references to functions
for _, use := range getUses(mod.NamedFunction("internal/task.getGoroutineStackSize")) {
if use.FirstUse().IsNil() {
// Apparently this stack size isn't used.
@@ -23,6 +24,7 @@ func CreateStackSizeLoads(mod llvm.Module, config *compileopts.Config) []string
if _, ok := functionMap[ptrtoint]; !ok {
functions = append(functions, ptrtoint)
functionNames = append(functionNames, ptrtoint.Operand(0).Name())
functionValues = append(functionValues, ptrtoint.Operand(0))
}
functionMap[ptrtoint] = append(functionMap[ptrtoint], use)
}
@@ -44,6 +46,9 @@ func CreateStackSizeLoads(mod llvm.Module, config *compileopts.Config) []string
}
stackSizesGlobal.SetInitializer(llvm.ConstArray(functions[0].Type(), defaultStackSizes))
// Add all relevant values to llvm.used (for LTO).
appendToUsedGlobals(mod, append([]llvm.Value{stackSizesGlobal}, functionValues...)...)
// Replace the calls with loads from the new global with stack sizes.
irbuilder := mod.Context().NewBuilder()
defer irbuilder.Dispose()
@@ -62,3 +67,22 @@ func CreateStackSizeLoads(mod llvm.Module, config *compileopts.Config) []string
return functionNames
}
// Append the given values to the llvm.used array. The values can be any pointer
// type, they will be bitcast to i8*.
func appendToUsedGlobals(mod llvm.Module, values ...llvm.Value) {
if !mod.NamedGlobal("llvm.used").IsNil() {
// Sanity check. TODO: we don't emit such a global at the moment, but
// when we do we should append to it instead.
panic("todo: append to existing llvm.used")
}
i8ptrType := llvm.PointerType(mod.Context().Int8Type(), 0)
var castValues []llvm.Value
for _, value := range values {
castValues = append(castValues, llvm.ConstBitCast(value, i8ptrType))
}
usedInitializer := llvm.ConstArray(i8ptrType, castValues)
used := llvm.AddGlobal(mod, usedInitializer.Type(), "llvm.used")
used.SetInitializer(usedInitializer)
used.SetLinkage(llvm.AppendingLinkage)
}
+1
View File
@@ -2,6 +2,7 @@ target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "armv7m-none-eabi"
@"internal/task.stackSizes" = global [1 x i32] [i32 1024], section ".tinygo_stacksizes"
@llvm.used = appending global [2 x i8*] [i8* bitcast ([1 x i32]* @"internal/task.stackSizes" to i8*), i8* bitcast (void (i8*)* @"runtime.run$1$gowrapper" to i8*)]
declare i32 @"internal/task.getGoroutineStackSize"(i32, i8*, i8*)