Compare commits

..

30 Commits

Author SHA1 Message Date
sago35 30d684e637 atsamd5x: add SPI.TxN() 2021-03-29 13:31:36 +09:00
Ayke van Laethem 90b42799a2 machine: make machine.I2C0 and similar objects pointers
This makes it possible to assign I2C objects (machine.I2C0,
machine.I2C1, etc.) without needing to take a pointer.

This is important especially in the future when I2C may be driven using
DMA and the machine.I2C type needs to store some state.
2021-03-29 02:02:04 +02:00
Ayke van Laethem 71bbe93ab2 avr: remove I2C stubs from attiny support
These stubs don't really belong there: attiny currently doesn't directly
support I2C at all (although it has hardware to support a software
implementation).
2021-03-29 02:02:04 +02:00
Elliott Sales de Andrade 0535c1bbad Group together STM32 smoke tests.
And then allow them to be disabled with one option.
2021-03-29 01:46:54 +02:00
Ayke van Laethem 4f6d598ea8 reflect: implement Sizeof and Alignof for func values
This is a small change that appears to be necessary for encoding/json
support. It's simple enough to implement.
2021-03-29 01:04:11 +02:00
sago35 16e7dd83a3 gdb: enable to specify multiple candidates for gdb 2021-03-29 00:21:38 +02:00
Olaf Flebbe f23ba3b023 initial support for pca10059
Using the official USB Vendor name even for other boards.
2021-03-28 21:38:05 +02:00
Ayke van Laethem 2aa2e750b9 reflect: implement Value.CanAddr
It is used in the crypto/sha512 test, for example. And it is very simple
to implement.
2021-03-28 19:28:55 +02:00
Ayke van Laethem bcce296ca3 transform: optimize reflect.Type Implements() method
This commit adds a new transform that converts reflect Implements()
calls to runtime.interfaceImplements. At the moment, the Implements()
method is not yet implemented (how ironic) but if the value passed to
Implements is known at compile time the method call can be optimized to
runtime.interfaceImplements to make it a regular interface assert.

This commit is the last change necessary to add basic support for the
encoding/json package. The json package is certainly not yet fully
supported, but some trivial objects can be converted to JSON.
2021-03-28 14:00:37 +02:00
Ayke van Laethem c5ec955081 compiler: fix lack of method name in interface matching
This is required for correctly differentiating between interface types.
2021-03-28 14:00:37 +02:00
Ayke van Laethem 5d334922d7 compiler: add interface IR test
This is important as golden test output and to verify that the output is
correct. Later improvements and bug fixes are clearly visible in the IR,
and unintentional changes will also be immediately spotted.
2021-03-28 14:00:37 +02:00
Ayke van Laethem e9f9a4b750 reflect: fix AssignableTo and Implements methods
They both reversed the direction of the check, in a way that mostly
cancelled each other out. Of course they're still mostly unimplemented,
but it's better if they're not wrong.
2021-03-28 14:00:37 +02:00
Takeshi Yoneda 1406453350 WASI & darwin: support basic file io based on libc
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
2021-03-28 12:37:15 +02:00
Ayke van Laethem 6d3c11627c compiler: fix use of global context: llvm.Int32Type()
This patch fixes a use of the global context. I've seen a few instances
of crashes in the llvm.ConstInt function when called from
makeStructTypeFields, which I believe are caused by this bug.
2021-03-25 13:05:09 +01:00
Ayke van Laethem f800f7507c reflect: check for access in the Interface method call
This fixes a type system loophole. The following program would
incorrectly run in TinyGo, while it would trigger a panic in Go:

    package main

    import "reflect"

    func main() {
        v := reflect.ValueOf(struct {
            x int
        }{})
        x := v.Field(0).Interface()
        println("x:", x.(int))
    }

Playground link: https://play.golang.org/p/nvvA18XFqFC

The panic in Go is the following:

    panic: reflect.Value.Interface: cannot return value obtained from unexported field or method

I've shortened it in TinyGo to save a little bit of space.
2021-03-24 12:19:16 +01:00
Kenneth Bell 46a7993fb8 stm32: i2c implementation for F7, L5 and L4 MCUs 2021-03-24 08:35:34 +01:00
Ayke van Laethem 9f3dcf3733 reflect: implement a number of stub functions
These stub functions are necessary for the encoding/json package. They
don't seem to be called in trivial cases, so leave them as simple stubs
for now.
2021-03-23 15:48:33 +01:00
Ayke van Laethem c849bccb83 reflect: let reflect.Type be of interface type
This matches the main Go implementation and (among others) fixes a
compatibility issue with the encoding/json package. The encoding/json
package compares reflect.Type variables against nil, which does not work
as long as reflect.Type is of integer type.

This also adds a reflect.RawType() function (like reflect.Type()) that
makes it easier to avoid working with interfaces in the runtime package.
It is internal only, but exported to let the runtime package use it.

This change introduces a small code size increase when working with the
reflect package, but I've tried to keep it to a minimum. Most programs
that don't make extensive use of the reflect package (and don't use
package like fmt) should not be impacted by this.
2021-03-23 14:32:33 +01:00
Ayke van Laethem cffe424849 interp: add support for runtime.interfaceMethod
This is necessary so that when reflect.Type is converted from a concrete
type to an interface type, the errors package can still be interpreted.
Without this change, basically every program would grow in size by a few
bytes.
2021-03-23 14:32:33 +01:00
Ayke van Laethem 51938e9d1c interp: handle (reflect.Type).Elem()
The errors package has a call like this in the package initializer. This
commit adds support for running it at compile time, avoiding the call at
runtime.

This doesn't always help (the call is already optimized away in many
small programs) but it does help to shave off some binary size in larger
programs. Perhaps more importantly, it will avoid a penalty in code size
when the reflect package will convert reflect.Type from a regular type
to an interface type.
2021-03-23 14:32:33 +01:00
Ayke van Laethem 19dec048b0 compiler: do not check for impossible type asserts
Previously there was code to avoid impossible type asserts but it wasn't
great and in fact was too aggressive when combined with reflection.

This commit improves this by checking all types that exist in the
program that may appear in an interface (even struct fields and the
like) but without creating runtime.typecodeID objects with the type
assert. This has two advantages:

  * As mentioned, it optimizes impossible type asserts away.
  * It allows methods on types that were only asserted on (in
    runtime.typeAssert) but never used in an interface to be optimized
    away using GlobalDCE. This may have a cascading effect so that other
    parts of the code can be further optimized.

This sometimes massively improves code size and mostly negates the code
size regression of the previous commit.
2021-03-23 14:32:33 +01:00
Ayke van Laethem bbb2909283 compiler: merge runtime.typecodeID and runtime.typeInInterface
This distinction was useful before when reflect wasn't properly
supported. Back then it made sense to only include method sets that were
actually used in an interface. But now that it is possible to get to
other values (for example, by extracting fields from structs) and it is
possible to turn them back into interfaces, it is necessary to preserve
all method sets that can possibly be used in the program in a type
assert, interface assert or interface method call.

In the future, this logic will need to be revisited again when
reflect.New or reflect.Zero gets implemented.

Code size increases a bit in some cases, but usually in a very limited
way (except for one outlier in the drivers smoke tests). The next commit
will improve the situation significantly.
2021-03-23 14:32:33 +01:00
Kenneth Bell aa7c7b7bd9 lgt92: update to new UART structure 2021-03-23 08:33:59 +01:00
Kenneth Bell c7bd5405c3 Add support for nucleol432 board
LED and UART are working
2021-03-23 08:33:59 +01:00
Kenneth Bell dc981ce509 stm32: separate altfunc selection for UART Tx/Rx
This is needed for stm32l432 nucleo with different altfun for tx and rx
2021-03-23 08:33:59 +01:00
Ayke van Laethem c522569378 wasm: only export explicitly exported functions
Previously we used the --export-all linker flag to export most
functions. However, this is not needed and possibly increases binary
size. Instead, we should be exporting the specific functions to be
exported.
2021-03-22 13:48:12 +01:00
Ayke van Laethem 0db4b13e37 compiler: do not emit nil checks for *ssa.Alloc instructions
An allocated object is never nil, so there is no need for a nil check.
This probably does not result in any better optimization (the nil check
is easily optimized away by LLVM because the result of runtime.alloc is
marked nonnull) but it makes the slice tests a bit cleaner.
2021-03-22 11:35:06 +01:00
Ayke van Laethem 2709d38d63 compiler: add some more slice tests 2021-03-22 11:35:06 +01:00
Ayke van Laethem 71d1b70ab7 compiler: only run tests on LLVM 11 or above
It's difficult to create clean test cases while remaining compatible
with multiple LLVM versions. Most test outputs are much more readable
after an instcombine pass but instcombine rules change between LLVM
versions, leading to different (but semantically equivalent) test
outputs.

This reduces the test coverage a little bit (because old LLVM versions
aren't tested as well), but it als makes it easier to add more complex
tests.

In the future it might be a good idea to make the compiler output a bit
less messy so these workarounds are not needed.
2021-03-22 11:35:06 +01:00
Ayke van Laethem 24676d4366 compiler: add tests for strings
This tests a few common operations on strings.
2021-03-22 11:35:06 +01:00
130 changed files with 2982 additions and 587 deletions
+31 -19
View File
@@ -107,7 +107,10 @@ fmt-check:
@unformatted=$$(gofmt -l $(FMT_PATHS)); [ -z "$$unformatted" ] && exit 0; echo "Unformatted:"; for fn in $$unformatted; do echo " $$fn"; done; exit 1
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-stm32 gen-device-kendryte gen-device-nxp
gen-device: gen-device-avr gen-device-esp gen-device-nrf gen-device-sam gen-device-sifive gen-device-kendryte gen-device-nxp
ifneq ($(STM32), 0)
gen-device: gen-device-stm32
endif
gen-device-avr:
@if [ ! -e lib/avr/README.md ]; then echo "Submodules have not been downloaded. Please download them using:\n git submodule update --init"; exit 1; fi
@@ -257,8 +260,6 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10031 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=reelboard examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=reelboard examples/blinky2
@@ -267,6 +268,10 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10056 examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10059 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10059 examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=itsybitsy-m0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-m0 examples/blinky1
@@ -275,14 +280,6 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-stm32f405 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-bluefruit examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=circuitplay-express examples/i2s
@@ -307,12 +304,8 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=particle-xenon examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-f103rb examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pinetime-devkit0 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=lgt92 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=x9pro examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pca10056-s140v7 examples/blinky1
@@ -339,10 +332,6 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=teensy36 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-f722ze examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-l552ze examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=p1am-100 examples/blinky1
@$(MD5SUM) test.hex
# test pwm
@@ -354,6 +343,28 @@ smoketest:
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=pyportal examples/pwm
@$(MD5SUM) test.hex
ifneq ($(STM32), 0)
$(TINYGO) build -size short -o test.hex -target=bluepill examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=feather-stm32f405 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=lgt92 examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-f103rb examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-f722ze examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-l432kc examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=nucleo-l552ze examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky1
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco examples/blinky2
@$(MD5SUM) test.hex
$(TINYGO) build -size short -o test.hex -target=stm32f4disco-1 examples/blinky1
@$(MD5SUM) test.hex
endif
ifneq ($(AVR), 0)
$(TINYGO) build -size short -o test.hex -target=atmega1284p examples/serial
@$(MD5SUM) test.hex
@@ -394,6 +405,7 @@ endif
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
@$(MD5SUM) test.hex
wasmtest:
$(GO) test ./tests/wasm
+18 -3
View File
@@ -7,6 +7,7 @@ import (
"errors"
"io"
"os"
"os/exec"
"path/filepath"
"reflect"
"runtime"
@@ -42,7 +43,7 @@ type TargetSpec struct {
ExtraFiles []string `json:"extra-files"`
Emulator []string `json:"emulator" override:"copy"` // inherited Emulator must not be append
FlashCommand string `json:"flash-command"`
GDB string `json:"gdb"`
GDB []string `json:"gdb"`
PortReset string `json:"flash-1200-bps-reset"`
FlashMethod string `json:"flash-method"`
FlashVolume string `json:"msd-volume-name"`
@@ -240,7 +241,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
Compiler: "clang",
Linker: "cc",
CFlags: []string{"--target=" + triple},
GDB: "gdb",
GDB: []string{"gdb"},
PortReset: "false",
}
if goos == "darwin" {
@@ -253,7 +254,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
}
if goarch != runtime.GOARCH {
// Some educated guesses as to how to invoke helper programs.
spec.GDB = "gdb-multiarch"
spec.GDB = []string{"gdb-multiarch"}
if goarch == "arm" && goos == "linux" {
spec.CFlags = append(spec.CFlags, "--sysroot=/usr/arm-linux-gnueabihf")
spec.Linker = "arm-linux-gnueabihf-gcc"
@@ -271,3 +272,17 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
}
return &spec, nil
}
// LookupGDB looks up a gdb executable.
func (spec *TargetSpec) LookupGDB() (string, error) {
if len(spec.GDB) == 0 {
return "", errors.New("gdb not configured in the target specification")
}
for _, d := range spec.GDB {
_, err := exec.LookPath(d)
if err == nil {
return d, nil
}
}
return "", errors.New("no gdb found configured in the target specification (" + strings.Join(spec.GDB, ", ") + ")")
}
+3
View File
@@ -159,6 +159,9 @@ func (b *builder) createNilCheck(inst ssa.Value, ptr llvm.Value, blockPrefix str
}
switch inst := inst.(type) {
case *ssa.Alloc:
// An alloc is never nil.
return
case *ssa.IndexAddr:
// This pointer is the result of an index operation into a slice or
// array. Such slices/arrays are already bounds checked so the pointer
+7 -1
View File
@@ -23,7 +23,7 @@ import (
// Version of the compiler pacakge. Must be incremented each time the compiler
// package changes in a way that affects the generated LLVM module.
// This version is independent of the TinyGo version number.
const Version = 1
const Version = 5 // last change: add method set to interface types
func init() {
llvm.InitializeAllTargets()
@@ -781,6 +781,12 @@ func (b *builder) createFunction() {
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
b.llvmFn.SetUnnamedAddr(true)
}
if b.info.exported && strings.HasPrefix(b.Triple, "wasm") {
// Set the exported name. This is necessary for WebAssembly because
// otherwise the function is not exported.
functionAttr := b.ctx.CreateStringAttribute("wasm-export-name", b.info.linkName)
b.llvmFn.AddFunctionAttr(functionAttr)
}
// Some functions have a pragma controlling the inlining level.
switch b.info.inline {
+15 -27
View File
@@ -4,7 +4,6 @@ import (
"flag"
"go/types"
"io/ioutil"
"regexp"
"strconv"
"strings"
"testing"
@@ -20,6 +19,19 @@ var flagUpdate = flag.Bool("update", false, "update tests based on test output")
// Basic tests for the compiler. Build some Go files and compare the output with
// the expected LLVM IR for regression testing.
func TestCompiler(t *testing.T) {
// Check LLVM version.
llvmMajor, err := strconv.Atoi(strings.SplitN(llvm.Version, ".", 2)[0])
if err != nil {
t.Fatal("could not parse LLVM version:", llvm.Version)
}
if llvmMajor < 11 {
// It is likely this version needs to be bumped in the future.
// The goal is to at least test the LLVM version that's used by default
// in TinyGo and (if possible without too many workarounds) also some
// previous versions.
t.Skip("compiler tests require LLVM 11 or above, got LLVM ", llvm.Version)
}
target, err := compileopts.LoadTarget("i686--linux")
if err != nil {
t.Fatal("failed to load target:", err)
@@ -47,7 +59,9 @@ func TestCompiler(t *testing.T) {
"basic.go",
"pointer.go",
"slice.go",
"string.go",
"float.go",
"interface.go",
}
for _, testCase := range tests {
@@ -108,8 +122,6 @@ func TestCompiler(t *testing.T) {
}
}
var alignRegexp = regexp.MustCompile(", align [0-9]+$")
// fuzzyEqualIR returns true if the two LLVM IR strings passed in are roughly
// equal. That means, only relevant lines are compared (excluding comments
// etc.).
@@ -121,15 +133,6 @@ func fuzzyEqualIR(s1, s2 string) bool {
}
for i, line1 := range lines1 {
line2 := lines2[i]
match1 := alignRegexp.MatchString(line1)
match2 := alignRegexp.MatchString(line2)
if match1 != match2 {
// Only one of the lines has the align keyword. Remove it.
// This is a change to make the test work in both LLVM 10 and LLVM
// 11 (LLVM 11 appears to automatically add alignment everywhere).
line1 = alignRegexp.ReplaceAllString(line1, "")
line2 = alignRegexp.ReplaceAllString(line2, "")
}
if line1 != line2 {
return false
}
@@ -143,12 +146,6 @@ func fuzzyEqualIR(s1, s2 string) bool {
// stripped out.
func filterIrrelevantIRLines(lines []string) []string {
var out []string
llvmVersion, err := strconv.Atoi(strings.Split(llvm.Version, ".")[0])
if err != nil {
// Note: this should never happen and if it does, it will always happen
// for a particular build because llvm.Version is a constant.
panic(err)
}
for _, line := range lines {
line = strings.Split(line, ";")[0] // strip out comments/info
line = strings.TrimRight(line, "\r ") // drop '\r' on Windows and remove trailing spaces from comments
@@ -158,15 +155,6 @@ func filterIrrelevantIRLines(lines []string) []string {
if strings.HasPrefix(line, "source_filename = ") {
continue
}
if llvmVersion < 10 && strings.HasPrefix(line, "attributes ") {
// Ignore attribute groups. These may change between LLVM versions.
// Right now test outputs are for LLVM 10.
continue
}
if llvmVersion < 10 && strings.HasPrefix(line, "target datalayout ") {
// Ignore the target layout. This may change between LLVM versions.
continue
}
out = append(out, line)
}
return out
+27 -18
View File
@@ -24,16 +24,7 @@ import (
func (b *builder) createMakeInterface(val llvm.Value, typ types.Type, pos token.Pos) llvm.Value {
itfValue := b.emitPointerPack([]llvm.Value{val})
itfTypeCodeGlobal := b.getTypeCode(typ)
itfMethodSetGlobal := b.getTypeMethodSet(typ)
itfConcreteTypeGlobal := b.mod.NamedGlobal("typeInInterface:" + itfTypeCodeGlobal.Name())
if itfConcreteTypeGlobal.IsNil() {
typeInInterface := b.getLLVMRuntimeType("typeInInterface")
itfConcreteTypeGlobal = llvm.AddGlobal(b.mod, typeInInterface, "typeInInterface:"+itfTypeCodeGlobal.Name())
itfConcreteTypeGlobal.SetInitializer(llvm.ConstNamedStruct(typeInInterface, []llvm.Value{itfTypeCodeGlobal, itfMethodSetGlobal}))
itfConcreteTypeGlobal.SetGlobalConstant(true)
itfConcreteTypeGlobal.SetLinkage(llvm.LinkOnceODRLinkage)
}
itfTypeCode := b.CreatePtrToInt(itfConcreteTypeGlobal, b.uintptrType, "")
itfTypeCode := b.CreatePtrToInt(itfTypeCodeGlobal, b.uintptrType, "")
itf := llvm.Undef(b.getLLVMRuntimeType("_interface"))
itf = b.CreateInsertValue(itf, itfTypeCode, 0, "")
itf = b.CreateInsertValue(itf, itfValue, 1, "")
@@ -54,6 +45,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
// reflect lowering simpler.
var references llvm.Value
var length int64
var methodSet llvm.Value
switch typ := typ.(type) {
case *types.Named:
references = c.getTypeCode(typ.Underlying())
@@ -70,15 +62,26 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
// Take a pointer to the typecodeID of the first field (if it exists).
structGlobal := c.makeStructTypeFields(typ)
references = llvm.ConstBitCast(structGlobal, global.Type())
case *types.Interface:
methodSetGlobal := c.getInterfaceMethodSet(typ)
references = llvm.ConstBitCast(methodSetGlobal, global.Type())
}
if !references.IsNil() {
if _, ok := typ.Underlying().(*types.Interface); !ok {
methodSet = c.getTypeMethodSet(typ)
}
if !references.IsNil() || length != 0 || !methodSet.IsNil() {
// Set the 'references' field of the runtime.typecodeID struct.
globalValue := llvm.ConstNull(global.Type().ElementType())
globalValue = llvm.ConstInsertValue(globalValue, references, []uint32{0})
if !references.IsNil() {
globalValue = llvm.ConstInsertValue(globalValue, references, []uint32{0})
}
if length != 0 {
lengthValue := llvm.ConstInt(c.uintptrType, uint64(length), false)
globalValue = llvm.ConstInsertValue(globalValue, lengthValue, []uint32{1})
}
if !methodSet.IsNil() {
globalValue = llvm.ConstInsertValue(globalValue, methodSet, []uint32{2})
}
global.SetInitializer(globalValue)
global.SetLinkage(llvm.LinkOnceODRLinkage)
}
@@ -103,8 +106,8 @@ func (c *compilerContext) makeStructTypeFields(typ *types.Struct) llvm.Value {
fieldName.SetLinkage(llvm.PrivateLinkage)
fieldName.SetUnnamedAddr(true)
fieldName = llvm.ConstGEP(fieldName, []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
})
fieldGlobalValue = llvm.ConstInsertValue(fieldGlobalValue, fieldName, []uint32{1})
if typ.Tag(i) != "" {
@@ -112,8 +115,8 @@ func (c *compilerContext) makeStructTypeFields(typ *types.Struct) llvm.Value {
fieldTag.SetLinkage(llvm.PrivateLinkage)
fieldTag.SetUnnamedAddr(true)
fieldTag = llvm.ConstGEP(fieldTag, []llvm.Value{
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(llvm.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
})
fieldGlobalValue = llvm.ConstInsertValue(fieldGlobalValue, fieldTag, []uint32{2})
}
@@ -186,7 +189,7 @@ func getTypeCodeName(t types.Type) string {
case *types.Interface:
methods := make([]string, t.NumMethods())
for i := 0; i < t.NumMethods(); i++ {
methods[i] = getTypeCodeName(t.Method(i).Type())
methods[i] = t.Method(i).Name() + ":" + getTypeCodeName(t.Method(i).Type())
}
return "interface:" + "{" + strings.Join(methods, ",") + "}"
case *types.Map:
@@ -338,10 +341,16 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
commaOk = b.createRuntimeCall("interfaceImplements", []llvm.Value{actualTypeNum, methodSet}, "")
} else {
globalName := "reflect/types.type:" + getTypeCodeName(expr.AssertedType) + "$id"
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
if assertedTypeCodeGlobal.IsNil() {
// Create a new typecode global.
assertedTypeCodeGlobal = llvm.AddGlobal(b.mod, b.ctx.Int8Type(), globalName)
assertedTypeCodeGlobal.SetGlobalConstant(true)
}
// Type assert on concrete type.
// Call runtime.typeAssert, which will be lowered to a simple icmp or
// const false in the interface lowering pass.
assertedTypeCodeGlobal := b.getTypeCode(expr.AssertedType)
commaOk = b.createRuntimeCall("typeAssert", []llvm.Value{actualTypeNum, assertedTypeCodeGlobal}, "typecode")
}
+3
View File
@@ -150,6 +150,9 @@ func (s *stdSizes) Sizeof(T types.Type) int64 {
return s.PtrSize * 2
case *types.Pointer:
return s.PtrSize
case *types.Signature:
// Func values in TinyGo are two words in size.
return s.PtrSize * 2
default:
panic("unknown type: " + t.String())
}
+54
View File
@@ -0,0 +1,54 @@
// This file tests interface types and interface builtins.
package main
// Test interface construction.
func simpleType() interface{} {
return 0
}
func pointerType() interface{} {
// Pointers have an element type, in this case int.
var v *int
return v
}
func interfaceType() interface{} {
// Interfaces can exist in interfaces, but only indirectly (through
// pointers).
var v *error
return v
}
func anonymousInterfaceType() interface{} {
var v *interface {
String() string
}
return v
}
// Test interface builtins.
func isInt(itf interface{}) bool {
_, ok := itf.(int)
return ok
}
func isError(itf interface{}) bool {
// Interface assert on (builtin) named interface type.
_, ok := itf.(error)
return ok
}
func isStringer(itf interface{}) bool {
// Interface assert on anonymous interface type.
_, ok := itf.(interface {
String() string
})
return ok
}
func callErrorMethod(itf error) string {
return itf.Error()
}
+100
View File
@@ -0,0 +1,100 @@
; ModuleID = 'interface.go'
source_filename = "interface.go"
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
target triple = "i686--linux"
%runtime.typecodeID = type { %runtime.typecodeID*, i32, %runtime.interfaceMethodInfo* }
%runtime.interfaceMethodInfo = type { i8*, i32 }
%runtime._interface = type { i32, i8* }
%runtime._string = type { i8*, i32 }
@"reflect/types.type:basic:int" = linkonce_odr constant %runtime.typecodeID zeroinitializer
@"reflect/types.type:pointer:basic:int" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i32 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.type:pointer:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:named:error", i32 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.type:named:error" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{Error:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.type:interface:{Error:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{Error() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null }
@"func Error() string" = external constant i8
@"reflect/types.interface:interface{Error() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func Error() string"]
@"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:interface:{String:func:{}{basic:string}}", i32 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{String() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null }
@"func String() string" = external constant i8
@"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func String() string"]
@"reflect/types.type:basic:int$id" = external constant i8
@"error$interface" = linkonce_odr constant [1 x i8*] [i8* @"func Error() string"]
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret void
}
define hidden %runtime._interface @main.simpleType(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:basic:int" to i32), i8* null }
}
define hidden %runtime._interface @main.pointerType(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:basic:int" to i32), i8* null }
}
define hidden %runtime._interface @main.interfaceType(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:named:error" to i32), i8* null }
}
define hidden %runtime._interface @main.anonymousInterfaceType(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret %runtime._interface { i32 ptrtoint (%runtime.typecodeID* @"reflect/types.type:pointer:interface:{String:func:{}{basic:string}}" to i32), i8* null }
}
define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.type:basic:int$id", i8* undef, i8* null)
br i1 %typecode, label %typeassert.ok, label %typeassert.next
typeassert.ok: ; preds = %entry
br label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry
ret i1 %typecode
}
declare i1 @runtime.typeAssert(i32, i8* dereferenceable_or_null(1), i8*, i8*)
define hidden i1 @main.isError(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = call i1 @runtime.interfaceImplements(i32 %itf.typecode, i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"error$interface", i32 0, i32 0), i8* undef, i8* null)
br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.ok: ; preds = %entry
br label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry
ret i1 %0
}
declare i1 @runtime.interfaceImplements(i32, i8** dereferenceable_or_null(4), i8*, i8*)
define hidden i1 @main.isStringer(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = call i1 @runtime.interfaceImplements(i32 %itf.typecode, i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"reflect/types.interface:interface{String() string}$interface", i32 0, i32 0), i8* undef, i8* null)
br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.ok: ; preds = %entry
br label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry
ret i1 %0
}
define hidden %runtime._string @main.callErrorMethod(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%invoke.func = call i32 @runtime.interfaceMethod(i32 %itf.typecode, i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"error$interface", i32 0, i32 0), i8* nonnull @"func Error() string", i8* undef, i8* null)
%invoke.func.cast = inttoptr i32 %invoke.func to %runtime._string (i8*, i8*, i8*)*
%0 = call %runtime._string %invoke.func.cast(i8* %itf.value, i8* undef, i8* undef)
ret %runtime._string %0
}
declare i32 @runtime.interfaceMethod(i32, i8** dereferenceable_or_null(4), i8* dereferenceable_or_null(1), i8*, i8*)
+16
View File
@@ -7,3 +7,19 @@ func sliceLen(ints []int) int {
func sliceCap(ints []int) int {
return cap(ints)
}
func sliceElement(ints []int, index int) int {
return ints[index]
}
func sliceAppendValues(ints []int) []int {
return append(ints, 1, 2, 3)
}
func sliceAppendSlice(ints, added []int) []int {
return append(ints, added...)
}
func sliceCopy(dst, src []int) int {
return copy(dst, src)
}
+67
View File
@@ -19,3 +19,70 @@ define hidden i32 @main.sliceCap(i32* %ints.data, i32 %ints.len, i32 %ints.cap,
entry:
ret i32 %ints.cap
}
define hidden i32 @main.sliceElement(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32 %index, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%.not = icmp ult i32 %index, %ints.len
br i1 %.not, label %lookup.next, label %lookup.throw
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(i8* undef, i8* null)
unreachable
lookup.next: ; preds = %entry
%0 = getelementptr inbounds i32, i32* %ints.data, i32 %index
%1 = load i32, i32* %0, align 4
ret i32 %1
}
declare void @runtime.lookupPanic(i8*, i8*)
define hidden { i32*, i32, i32 } @main.sliceAppendValues(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%varargs = call i8* @runtime.alloc(i32 12, i8* undef, i8* null)
%0 = bitcast i8* %varargs to i32*
store i32 1, i32* %0, align 4
%1 = getelementptr inbounds i8, i8* %varargs, i32 4
%2 = bitcast i8* %1 to i32*
store i32 2, i32* %2, align 4
%3 = getelementptr inbounds i8, i8* %varargs, i32 8
%4 = bitcast i8* %3 to i32*
store i32 3, i32* %4, align 4
%append.srcPtr = bitcast i32* %ints.data to i8*
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* nonnull %varargs, i32 %ints.len, i32 %ints.cap, i32 3, i32 4, i8* undef, i8* null)
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
%append.newBuf = bitcast i8* %append.newPtr to i32*
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
%append.newCap = extractvalue { i8*, i32, i32 } %append.new, 2
%5 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
%6 = insertvalue { i32*, i32, i32 } %5, i32 %append.newLen, 1
%7 = insertvalue { i32*, i32, i32 } %6, i32 %append.newCap, 2
ret { i32*, i32, i32 } %7
}
declare { i8*, i32, i32 } @runtime.sliceAppend(i8*, i8*, i32, i32, i32, i32, i8*, i8*)
define hidden { i32*, i32, i32 } @main.sliceAppendSlice(i32* %ints.data, i32 %ints.len, i32 %ints.cap, i32* %added.data, i32 %added.len, i32 %added.cap, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%append.srcPtr = bitcast i32* %ints.data to i8*
%append.srcPtr1 = bitcast i32* %added.data to i8*
%append.new = call { i8*, i32, i32 } @runtime.sliceAppend(i8* %append.srcPtr, i8* %append.srcPtr1, i32 %ints.len, i32 %ints.cap, i32 %added.len, i32 4, i8* undef, i8* null)
%append.newPtr = extractvalue { i8*, i32, i32 } %append.new, 0
%append.newBuf = bitcast i8* %append.newPtr to i32*
%append.newLen = extractvalue { i8*, i32, i32 } %append.new, 1
%append.newCap = extractvalue { i8*, i32, i32 } %append.new, 2
%0 = insertvalue { i32*, i32, i32 } undef, i32* %append.newBuf, 0
%1 = insertvalue { i32*, i32, i32 } %0, i32 %append.newLen, 1
%2 = insertvalue { i32*, i32, i32 } %1, i32 %append.newCap, 2
ret { i32*, i32, i32 } %2
}
define hidden i32 @main.sliceCopy(i32* %dst.data, i32 %dst.len, i32 %dst.cap, i32* %src.data, i32 %src.len, i32 %src.cap, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%copy.dstPtr = bitcast i32* %dst.data to i8*
%copy.srcPtr = bitcast i32* %src.data to i8*
%copy.n = call i32 @runtime.sliceCopy(i8* %copy.dstPtr, i8* %copy.srcPtr, i32 %dst.len, i32 %src.len, i32 4, i8* undef, i8* null)
ret i32 %copy.n
}
declare i32 @runtime.sliceCopy(i8*, i8*, i32, i32, i32, i8*, i8*)
+21
View File
@@ -0,0 +1,21 @@
package main
func stringLen(s string) int {
return len(s)
}
func stringIndex(s string, index int) byte {
return s[index]
}
func stringCompareEqual(s1, s2 string) bool {
return s1 == s2
}
func stringCompareUnequal(s1, s2 string) bool {
return s1 != s2
}
func stringCompareLarger(s1, s2 string) bool {
return s1 > s2
}
+57
View File
@@ -0,0 +1,57 @@
; ModuleID = 'string.go'
source_filename = "string.go"
target datalayout = "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-f64:32:64-f80:32-n8:16:32-S128"
target triple = "i686--linux"
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret void
}
define hidden i32 @main.stringLen(i8* %s.data, i32 %s.len, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
ret i32 %s.len
}
define hidden i8 @main.stringIndex(i8* %s.data, i32 %s.len, i32 %index, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%.not = icmp ult i32 %index, %s.len
br i1 %.not, label %lookup.next, label %lookup.throw
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(i8* undef, i8* null)
unreachable
lookup.next: ; preds = %entry
%0 = getelementptr inbounds i8, i8* %s.data, i32 %index
%1 = load i8, i8* %0, align 1
ret i8 %1
}
declare void @runtime.lookupPanic(i8*, i8*)
define hidden i1 @main.stringCompareEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null)
ret i1 %0
}
declare i1 @runtime.stringEqual(i8*, i32, i8*, i32, i8*, i8*)
define hidden i1 @main.stringCompareUnequal(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = call i1 @runtime.stringEqual(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null)
%1 = xor i1 %0, true
ret i1 %1
}
define hidden i1 @main.stringCompareLarger(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
%0 = call i1 @runtime.stringLess(i8* %s1.data, i32 %s1.len, i8* %s2.data, i32 %s2.len, i8* undef, i8* null)
%1 = xor i1 %0, true
ret i1 %1
}
declare i1 @runtime.stringLess(i8*, i32, i8*, i32, i8*, i8*)
+72 -20
View File
@@ -155,11 +155,8 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
// which case this call won't even get to this point but will
// already be emitted in initAll.
continue
case callFn.name == "(reflect.Type).Elem" || strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet":
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet":
// These functions should be run at runtime. Specifically:
// * (reflect.Type).Elem is a special function. It should
// eventually be interpreted, but fall back to a runtime call
// for now.
// * Print and panic functions are best emitted directly without
// interpreting them, otherwise we get a ton of putchar (etc.)
// calls.
@@ -280,26 +277,48 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
copy(dstBuf.buf[dst.offset():dst.offset()+nBytes], srcBuf.buf[src.offset():])
dstObj.buffer = dstBuf
mem.put(dst.index(), dstObj)
case callFn.name == "(reflect.rawType).elem":
if r.debug {
fmt.Fprintln(os.Stderr, indent+"call (reflect.rawType).elem:", operands[1:])
}
// Extract the type code global from the first parameter.
typecodeID := operands[1].toLLVMValue(inst.llvmInst.Operand(0).Type(), &mem).Operand(0)
// Get the type class.
// See also: getClassAndValueFromTypeCode in transform/reflect.go.
typecodeName := typecodeID.Name()
const prefix = "reflect/types.type:"
if !strings.HasPrefix(typecodeName, prefix) {
panic("unexpected typecode name: " + typecodeName)
}
id := typecodeName[len(prefix):]
class := id[:strings.IndexByte(id, ':')]
value := id[len(class)+1:]
if class == "named" {
// Get the underlying type.
class = value[:strings.IndexByte(value, ':')]
value = value[len(class)+1:]
}
// Elem() is only valid for certain type classes.
switch class {
case "chan", "pointer", "slice", "array":
elementType := llvm.ConstExtractValue(typecodeID.Initializer(), []uint32{0})
uintptrType := r.mod.Context().IntType(int(mem.r.pointerSize) * 8)
locals[inst.localIndex] = r.getValue(llvm.ConstPtrToInt(elementType, uintptrType))
default:
return nil, mem, r.errorAt(inst, fmt.Errorf("(reflect.Type).Elem() called on %s type", class))
}
case callFn.name == "runtime.typeAssert":
// This function must be implemented manually as it is normally
// implemented by the interface lowering pass.
if r.debug {
fmt.Fprintln(os.Stderr, indent+"typeassert:", operands[1:])
}
typeInInterfacePtr, err := operands[1].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
actualType, err := mem.load(typeInInterfacePtr, r.pointerSize).asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
assertedType, err := operands[2].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
result := assertedType.asRawValue(r).equal(actualType.asRawValue(r))
if result {
assertedType := operands[2].toLLVMValue(inst.llvmInst.Operand(1).Type(), &mem)
actualTypePtrToInt := operands[1].toLLVMValue(inst.llvmInst.Operand(0).Type(), &mem)
actualType := actualTypePtrToInt.Operand(0)
if actualType.Name()+"$id" == assertedType.Name() {
locals[inst.localIndex] = literalValue{uint8(1)}
} else {
locals[inst.localIndex] = literalValue{uint8(0)}
@@ -310,11 +329,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
}
// Load various values for the interface implements check below.
typeInInterfacePtr, err := operands[1].asPointer(r)
typecodePtr, err := operands[1].asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
methodSetPtr, err := mem.load(typeInInterfacePtr.addOffset(r.pointerSize), r.pointerSize).asPointer(r)
methodSetPtr, err := mem.load(typecodePtr.addOffset(r.pointerSize*2), r.pointerSize).asPointer(r)
if err != nil {
return nil, mem, r.errorAt(inst, err)
}
@@ -349,6 +368,39 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
}
// If assertOk is still 1, the assertion succeeded.
locals[inst.localIndex] = literalValue{assertOk}
case callFn.name == "runtime.interfaceMethod":
// This builtin returns the function (which may be a thunk) to
// invoke a method on an interface. It does not call the method.
if r.debug {
fmt.Fprintln(os.Stderr, indent+"interface method:", operands[1:])
}
// Load the first param, which is the type code (ptrtoint of the
// type code global).
typecodeID := operands[1].toLLVMValue(inst.llvmInst.Operand(0).Type(), &mem).Operand(0).Initializer()
// Load the method set, which is part of the typecodeID object.
methodSet := llvm.ConstExtractValue(typecodeID, []uint32{2}).Operand(0).Initializer()
// We don't need to load the interface method set.
// Load the signature of the to-be-called function.
signature := inst.llvmInst.Operand(2)
// Iterate through all methods, looking for the one method that
// should be returned.
numMethods := methodSet.Type().ArrayLength()
var method llvm.Value
for i := 0; i < numMethods; i++ {
methodSignature := llvm.ConstExtractValue(methodSet, []uint32{uint32(i), 0})
if methodSignature == signature {
method = llvm.ConstExtractValue(methodSet, []uint32{uint32(i), 1}).Operand(0)
}
}
if method.IsNil() {
return nil, mem, r.errorAt(inst, errors.New("could not find method: "+signature.Name()))
}
locals[inst.localIndex] = r.getValue(method)
case callFn.name == "runtime.hashmapMake":
// Create a new map.
hashmapPointerType := inst.llvmInst.Type()
+1 -1
View File
@@ -1048,7 +1048,7 @@ func (v rawValue) rawLLVMValue(mem *memoryView) llvm.Value {
// There are some special pointer types that should be used as a
// ptrtoint, so that they can be used in certain optimizations.
name := elementType.StructName()
if name == "runtime.typeInInterface" || name == "runtime.funcValueWithSignature" {
if name == "runtime.typecodeID" || name == "runtime.funcValueWithSignature" {
uintptrType := ctx.IntType(int(mem.r.pointerSize) * 8)
field = llvm.ConstPtrToInt(field, uintptrType)
}
+5 -6
View File
@@ -1,17 +1,16 @@
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64--linux"
%runtime.typecodeID = type { %runtime.typecodeID*, i64 }
%runtime.typecodeID = type { %runtime.typecodeID*, i64, %runtime.interfaceMethodInfo* }
%runtime.interfaceMethodInfo = type { i8*, i64 }
%runtime.typeInInterface = type { %runtime.typecodeID*, %runtime.interfaceMethodInfo* }
@main.v1 = global i1 0
@"reflect/types.type:named:main.foo" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i64 0 }
@"reflect/types.type:named:main.foo" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i64 0, %runtime.interfaceMethodInfo* null }
@"reflect/types.type:named:main.foo$id" = external constant i8
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
@"typeInInterface:reflect/types.type:named:main.foo" = private constant %runtime.typeInInterface { %runtime.typecodeID* @"reflect/types.type:named:main.foo", %runtime.interfaceMethodInfo* null }
declare i1 @runtime.typeAssert(i64, %runtime.typecodeID*, i8*, i8*)
declare i1 @runtime.typeAssert(i64, i8*, i8*, i8*)
define void @runtime.initAll() unnamed_addr {
entry:
@@ -22,7 +21,7 @@ entry:
define internal void @main.init() unnamed_addr {
entry:
; Test type asserts.
%typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typeInInterface* @"typeInInterface:reflect/types.type:named:main.foo" to i64), %runtime.typecodeID* @"reflect/types.type:named:main.foo", i8* undef, i8* null)
%typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typecodeID* @"reflect/types.type:named:main.foo" to i64), i8* @"reflect/types.type:named:main.foo$id", i8* undef, i8* null)
store i1 %typecode, i1* @main.v1
ret void
}
+4 -3
View File
@@ -344,8 +344,9 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
if err != nil {
return err
}
if config.Target.GDB == "" {
return errors.New("gdb not configured in the target specification")
gdb, err := config.Target.LookupGDB()
if err != nil {
return err
}
return builder.Build(pkgName, "", config, func(result builder.BuildResult) error {
@@ -490,7 +491,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
for _, cmd := range gdbCommands {
params = append(params, "-ex", cmd)
}
cmd := executeCommand(config.Options, config.Target.GDB, params...)
cmd := executeCommand(config.Options, gdb, params...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
+10 -5
View File
@@ -59,7 +59,10 @@ func TestCompiler(t *testing.T) {
t.Run("Host", func(t *testing.T) {
runPlatTests("", matches, t)
if runtime.GOOS == "darwin" {
runTest("testdata/libc/env.go", "", t, []string{"ENV1=VALUE1", "ENV2=VALUE2"}...)
runTest("testdata/libc/filesystem.go", "", t,
nil, nil)
runTest("testdata/libc/env.go", "", t,
[]string{"ENV1=VALUE1", "ENV2=VALUE2"}, nil)
}
})
}
@@ -107,7 +110,9 @@ func TestCompiler(t *testing.T) {
t.Run("WASI", func(t *testing.T) {
runPlatTests("wasi", matches, t)
runTest("testdata/libc/env.go", "wasi", t, []string{"ENV1=VALUE1", "ENV2=VALUE2"}...)
runTest("testdata/libc/env.go", "wasi", t,
[]string{"--env", "ENV1=VALUE1", "--env", "ENV2=VALUE2"}, nil)
runTest("testdata/libc/filesystem.go", "wasi", t, nil, []string{"--dir=."})
})
}
}
@@ -119,7 +124,7 @@ func runPlatTests(target string, matches []string, t *testing.T) {
path := path // redefine to avoid race condition
t.Run(filepath.Base(path), func(t *testing.T) {
t.Parallel()
runTest(path, target, t)
runTest(path, target, t, nil, nil)
})
}
}
@@ -136,7 +141,7 @@ func runBuild(src, out string, opts *compileopts.Options) error {
return Build(src, out, opts)
}
func runTest(path, target string, t *testing.T, environmentVars ...string) {
func runTest(path, target string, t *testing.T, environmentVars []string, additionalArgs []string) {
// Get the expected output for this test.
txtpath := path[:len(path)-3] + ".txt"
if path[len(path)-1] == os.PathSeparator {
@@ -195,7 +200,7 @@ func runTest(path, target string, t *testing.T, environmentVars ...string) {
cmd = exec.Command(binary)
} else {
args := append(spec.Emulator[1:], binary)
cmd = exec.Command(spec.Emulator[0], args...)
cmd = exec.Command(spec.Emulator[0], append(args, additionalArgs...)...)
}
if len(spec.Emulator) != 0 && spec.Emulator[0] == "wasmtime" {
+2 -2
View File
@@ -11,7 +11,7 @@ import (
type rawState uint8
//export llvm.coro.resume
func (s *rawState) resume()
func coroResume(*rawState)
type state struct{ *rawState }
@@ -20,7 +20,7 @@ func noopState() *rawState
// Resume the task until it pauses or completes.
func (t *Task) Resume() {
t.state.resume()
coroResume(t.state.rawState)
}
// setState is used by the compiler to set the state of the function at the beginning of a function call.
@@ -32,7 +32,7 @@ func init() {
// I2C on the Arduino Nano 33.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM4_I2CM,
SERCOM: 4,
}
@@ -23,12 +23,12 @@ func init() {
// I2C on the Circuit Playground Express.
var (
// external device
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM5_I2CM,
SERCOM: 5,
}
// internal device
I2C1 = I2C{
I2C1 = &I2C{
Bus: sam.SERCOM1_I2CM,
SERCOM: 1,
}
+1 -1
View File
@@ -75,7 +75,7 @@ const (
// I2C on the Feather M0.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM3_I2CM,
SERCOM: 3,
}
+1 -1
View File
@@ -28,7 +28,7 @@ func init() {
// I2C on the Feather M4.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM2_I2CM,
SERCOM: 2,
}
+15 -12
View File
@@ -120,19 +120,22 @@ const (
var (
UART1 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.USART3,
AltFuncSelector: AF7_USART1_2_3,
Buffer: NewRingBuffer(),
Bus: stm32.USART3,
TxAltFuncSelector: AF7_USART1_2_3,
RxAltFuncSelector: AF7_USART1_2_3,
}
UART2 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.USART6,
AltFuncSelector: AF8_USART4_5_6,
Buffer: NewRingBuffer(),
Bus: stm32.USART6,
TxAltFuncSelector: AF8_USART4_5_6,
RxAltFuncSelector: AF8_USART4_5_6,
}
UART3 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.USART1,
AltFuncSelector: AF7_USART1_2_3,
Buffer: NewRingBuffer(),
Bus: stm32.USART1,
TxAltFuncSelector: AF7_USART1_2_3,
RxAltFuncSelector: AF7_USART1_2_3,
}
UART0 = UART1
)
@@ -227,15 +230,15 @@ const (
)
var (
I2C1 = I2C{
I2C1 = &I2C{
Bus: stm32.I2C1,
AltFuncSelector: AF4_I2C1_2_3,
}
I2C2 = I2C{
I2C2 = &I2C{
Bus: stm32.I2C2,
AltFuncSelector: AF4_I2C1_2_3,
}
I2C3 = I2C{
I2C3 = &I2C{
Bus: stm32.I2C1,
AltFuncSelector: AF4_I2C1_2_3,
}
@@ -40,11 +40,11 @@ var (
// I2C on the Grand Central M4
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM3_I2CM,
SERCOM: 3,
}
I2C1 = I2C{
I2C1 = &I2C{
Bus: sam.SERCOM6_I2CM,
SERCOM: 6,
}
-7
View File
@@ -10,10 +10,3 @@ var (
Bus: sifive.QSPI1,
}
)
// I2C on the HiFive1 rev B.
var (
I2C0 = I2C{
Bus: sifive.I2C0,
}
)
+1 -1
View File
@@ -75,7 +75,7 @@ const (
// I2C on the ItsyBitsy M0.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM3_I2CM,
SERCOM: 3,
}
+1 -1
View File
@@ -28,7 +28,7 @@ func init() {
// I2C on the ItsyBitsy M4.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM2_I2CM,
SERCOM: 2,
}
+8 -6
View File
@@ -54,16 +54,18 @@ var (
// Console UART (LPUSART1)
UART0 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.LPUART1,
AltFuncSelector: 6,
Buffer: NewRingBuffer(),
Bus: stm32.LPUART1,
TxAltFuncSelector: 6,
RxAltFuncSelector: 6,
}
// Gps UART
UART1 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.USART1,
AltFuncSelector: 0,
Buffer: NewRingBuffer(),
Bus: stm32.USART1,
TxAltFuncSelector: 0,
RxAltFuncSelector: 0,
}
// SPI
-13
View File
@@ -13,16 +13,3 @@ var (
Bus: kendryte.SPI1,
}
)
// I2C on the MAix Bit.
var (
I2C0 = I2C{
Bus: kendryte.I2C0,
}
I2C1 = I2C{
Bus: kendryte.I2C1,
}
I2C2 = I2C{
Bus: kendryte.I2C2,
}
)
@@ -29,7 +29,7 @@ func init() {
// I2C on the MatrixPortal M4
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM5_I2CM,
SERCOM: 5,
}
@@ -28,7 +28,7 @@ func init() {
// I2C on the Metro M4.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM5_I2CM,
SERCOM: 5,
}
+1 -1
View File
@@ -44,7 +44,7 @@ const (
// USB CDC identifiers
const (
usb_STRING_PRODUCT = "Makerdiary nRF52840 MDK USB Dongle"
usb_STRING_MANUFACTURER = "Makerdiary"
usb_STRING_MANUFACTURER = "Nordic Semiconductor ASA"
)
var (
+1 -1
View File
@@ -39,7 +39,7 @@ const (
// USB CDC identifiers
const (
usb_STRING_PRODUCT = "Makerdiary nRF52840 MDK"
usb_STRING_MANUFACTURER = "Makerdiary"
usb_STRING_MANUFACTURER = "Nordic Semiconductor ASA"
)
var (
+15 -5
View File
@@ -33,9 +33,10 @@ var (
// debugger to be exposed as virtual COM port over USB on Nucleo boards.
// Both UART0 and UART1 refer to USART2.
UART0 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.USART3,
AltFuncSelector: UART_ALT_FN,
Buffer: NewRingBuffer(),
Bus: stm32.USART3,
TxAltFuncSelector: UART_ALT_FN,
RxAltFuncSelector: UART_ALT_FN,
}
UART1 = &UART0
)
@@ -53,6 +54,15 @@ const (
// I2C pins
const (
SCL_PIN = PB6
SDA_PIN = PB7
I2C0_SCL_PIN = PB8
I2C0_SDA_PIN = PB9
)
var (
// I2C1 is documented, alias to I2C0 as well
I2C1 = &I2C{
Bus: stm32.I2C1,
AltFuncSelector: 4,
}
I2C0 = I2C1
)
+56
View File
@@ -0,0 +1,56 @@
// +build nucleol432kc
package machine
import (
"device/stm32"
"runtime/interrupt"
)
const (
LED = LED_BUILTIN
LED_BUILTIN = LED_GREEN
LED_GREEN = PB3
)
// UART pins
const (
// PA2 and PA15 are connected to the ST-Link Virtual Com Port (VCP)
UART_TX_PIN = PA2
UART_RX_PIN = PA15
)
// I2C pins
const (
// With default solder bridge settings:
// PB6 / Arduino D5 / CN3 Pin 8 is SCL
// PB7 / Arduino D4 / CN3 Pin 7 is SDA
I2C0_SCL_PIN = PB6
I2C0_SDA_PIN = PB7
)
var (
// USART2 is the hardware serial port connected to the onboard ST-LINK
// debugger to be exposed as virtual COM port over USB on Nucleo boards.
// Both UART0 and UART1 refer to USART2.
UART0 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.USART2,
TxAltFuncSelector: 7,
RxAltFuncSelector: 3,
}
UART1 = &UART0
)
var (
// I2C1 is documented, alias to I2C0 as well
I2C1 = &I2C{
Bus: stm32.I2C1,
AltFuncSelector: 4,
}
I2C0 = I2C1
)
func init() {
UART0.Interrupt = interrupt.New(stm32.IRQ_USART2, UART0.handleInterrupt)
}
+18 -3
View File
@@ -33,13 +33,28 @@ var (
// debugger to be exposed as virtual COM port over USB on Nucleo boards.
// Both UART0 and UART1 refer to LPUART1.
UART0 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.LPUART1,
AltFuncSelector: UART_ALT_FN,
Buffer: NewRingBuffer(),
Bus: stm32.LPUART1,
TxAltFuncSelector: UART_ALT_FN,
RxAltFuncSelector: UART_ALT_FN,
}
UART1 = &UART0
)
const (
I2C0_SCL_PIN = PB8
I2C0_SDA_PIN = PB9
)
var (
// I2C1 is documented, alias to I2C0 as well
I2C1 = &I2C{
Bus: stm32.I2C1,
AltFuncSelector: 4,
}
I2C0 = I2C1
)
func init() {
UART0.Interrupt = interrupt.New(stm32.IRQ_LPUART1, UART0.handleInterrupt)
}
+1 -1
View File
@@ -22,7 +22,7 @@ func init() {
// I2C on the P1AM-100.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM0_I2CM,
SERCOM: 0,
}
+64
View File
@@ -0,0 +1,64 @@
// +build pca10059
package machine
// The PCA10040 has a low-frequency (32kHz) crystal oscillator on board.
const HasLowFrequencyCrystal = true
// LEDs on the PCA10059 (nRF52840 dongle)
const (
LED Pin = LED1
LED1 Pin = 6
LED2 Pin = 8
LED3 Pin = (1 << 5) | 9
LED4 Pin = 12
)
// Buttons on the PCA10059 (nRF52840 dongle)
const (
BUTTON Pin = BUTTON1
BUTTON1 Pin = (1 << 5) | 6
)
// ADC pins
const (
ADC1 Pin = 2
ADC2 Pin = 4
ADC3 Pin = 29
ADC4 Pin = 31
)
// UART pins
const (
UART_TX_PIN Pin = NoPin
UART_RX_PIN Pin = NoPin
)
// UART0 is the USB device
var (
UART0 = USB
)
// I2C pins (unused)
const (
SDA_PIN = NoPin
SCL_PIN = NoPin
)
// SPI pins (unused)
const (
SPI0_SCK_PIN = NoPin
SPI0_SDO_PIN = NoPin
SPI0_SDI_PIN = NoPin
)
// USB CDC identifiers
const (
usb_STRING_PRODUCT = "nRF52840 Dongle"
usb_STRING_MANUFACTURER = "Nordic Semiconductor ASA"
)
var (
usb_VID uint16 = 0x1915
usb_PID uint16 = 0xCAFE
)
+1 -1
View File
@@ -28,7 +28,7 @@ func init() {
// I2C on the ItsyBitsy M4.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM2_I2CM,
SERCOM: 2,
}
+1 -1
View File
@@ -99,7 +99,7 @@ const (
// I2C on the PyGamer.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM2_I2CM,
SERCOM: 2,
}
+1 -1
View File
@@ -21,7 +21,7 @@ func init() {
// I2C on the PyPortal.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM5_I2CM,
SERCOM: 5,
}
+1 -1
View File
@@ -93,7 +93,7 @@ const (
// I2C on the QT Py M0.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM2_I2CM,
SERCOM: 2,
}
+5 -4
View File
@@ -28,9 +28,10 @@ const (
var (
UART0 = UART{
Buffer: NewRingBuffer(),
Bus: stm32.USART2,
AltFuncSelector: AF7_USART1_2_3,
Buffer: NewRingBuffer(),
Bus: stm32.USART2,
TxAltFuncSelector: AF7_USART1_2_3,
RxAltFuncSelector: AF7_USART1_2_3,
}
UART1 = &UART0
)
@@ -73,7 +74,7 @@ const (
)
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: stm32.I2C1,
AltFuncSelector: AF4_I2C1_2_3,
}
+1 -1
View File
@@ -81,7 +81,7 @@ const (
// I2C on the Trinket M0.
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM2_I2CM,
SERCOM: 2,
}
+2 -2
View File
@@ -29,12 +29,12 @@ func init() {
// I2C on the Wio Terminal
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM4_I2CM,
SERCOM: 4,
}
I2C1 = I2C{
I2C1 = &I2C{
Bus: sam.SERCOM4_I2CM,
SERCOM: 4,
}
+1 -1
View File
@@ -81,7 +81,7 @@ const (
// I2C on the Xiao
var (
I2C0 = I2C{
I2C0 = &I2C{
Bus: sam.SERCOM2_I2CM,
SERCOM: 2,
}
+3 -3
View File
@@ -1,4 +1,4 @@
// +build avr nrf sam stm32,!stm32f7x2,!stm32l5x2,!stm32l0 fe310 k210
// +build atmega nrf sam stm32,!stm32l0 fe310 k210
package machine
@@ -29,7 +29,7 @@ var (
// Many I2C-compatible devices are organized in terms of registers. This method
// is a shortcut to easily write to such registers. Also, it only works for
// devices with 7-bit addresses, which is the vast majority.
func (i2c I2C) WriteRegister(address uint8, register uint8, data []byte) error {
func (i2c *I2C) WriteRegister(address uint8, register uint8, data []byte) error {
buf := make([]uint8, len(data)+1)
buf[0] = register
copy(buf[1:], data)
@@ -42,6 +42,6 @@ func (i2c I2C) WriteRegister(address uint8, register uint8, data []byte) error {
// Many I2C-compatible devices are organized in terms of registers. This method
// is a shortcut to easily read such registers. Also, it only works for devices
// with 7-bit addresses, which is the vast majority.
func (i2c I2C) ReadRegister(address uint8, register uint8, data []byte) error {
func (i2c *I2C) ReadRegister(address uint8, register uint8, data []byte) error {
return i2c.Tx(uint16(address), []byte{register}, data)
}
+13 -6
View File
@@ -9,13 +9,20 @@ import (
"unsafe"
)
// I2C on AVR.
type I2C struct {
}
// I2C0 is the only I2C interface on most AVRs.
var I2C0 *I2C = nil
// I2CConfig is used to store config info for I2C.
type I2CConfig struct {
Frequency uint32
}
// Configure is intended to setup the I2C interface.
func (i2c I2C) Configure(config I2CConfig) error {
func (i2c *I2C) Configure(config I2CConfig) error {
// Default I2C bus speed is 100 kHz.
if config.Frequency == 0 {
config.Frequency = TWI_FREQ_100KHZ
@@ -42,7 +49,7 @@ func (i2c I2C) Configure(config I2CConfig) error {
// Tx does a single I2C transaction at the specified address.
// It clocks out the given address, writes the bytes in w, reads back len(r)
// bytes and stores them in r, and generates a stop condition on the bus.
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
if len(w) != 0 {
i2c.start(uint8(addr), true) // start transmission for writing
for _, b := range w {
@@ -63,7 +70,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// start starts an I2C communication session.
func (i2c I2C) start(address uint8, write bool) {
func (i2c *I2C) start(address uint8, write bool) {
// Clear TWI interrupt flag, put start condition on SDA, and enable TWI.
avr.TWCR.Set((avr.TWCR_TWINT | avr.TWCR_TWSTA | avr.TWCR_TWEN))
@@ -80,7 +87,7 @@ func (i2c I2C) start(address uint8, write bool) {
}
// stop ends an I2C communication session.
func (i2c I2C) stop() {
func (i2c *I2C) stop() {
// Send stop condition.
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWSTO)
@@ -90,7 +97,7 @@ func (i2c I2C) stop() {
}
// writeByte writes a single byte to the I2C bus.
func (i2c I2C) writeByte(data byte) {
func (i2c *I2C) writeByte(data byte) {
// Write data to register.
avr.TWDR.Set(data)
@@ -103,7 +110,7 @@ func (i2c I2C) writeByte(data byte) {
}
// readByte reads a single byte from the I2C bus.
func (i2c I2C) readByte() byte {
func (i2c *I2C) readByte() byte {
// Clear TWI interrupt flag and enable TWI.
avr.TWCR.Set(avr.TWCR_TWEN | avr.TWCR_TWINT | avr.TWCR_TWEA)
+8 -8
View File
@@ -669,7 +669,7 @@ const (
const i2cTimeout = 1000
// Configure is intended to setup the I2C interface.
func (i2c I2C) Configure(config I2CConfig) error {
func (i2c *I2C) Configure(config I2CConfig) error {
// Default I2C bus speed is 100 kHz.
if config.Frequency == 0 {
config.Frequency = TWI_FREQ_100KHZ
@@ -725,7 +725,7 @@ func (i2c I2C) Configure(config I2CConfig) error {
}
// SetBaudRate sets the communication speed for the I2C.
func (i2c I2C) SetBaudRate(br uint32) {
func (i2c *I2C) SetBaudRate(br uint32) {
// Synchronous arithmetic baudrate, via Arduino SAMD implementation:
// SystemCoreClock / ( 2 * baudrate) - 5 - (((SystemCoreClock / 1000000) * WIRE_RISE_TIME_NANOSECONDS) / (2 * 1000));
baud := CPUFrequency()/(2*br) - 5 - (((CPUFrequency() / 1000000) * riseTimeNanoseconds) / (2 * 1000))
@@ -735,7 +735,7 @@ func (i2c I2C) SetBaudRate(br uint32) {
// Tx does a single I2C transaction at the specified address.
// It clocks out the given address, writes the bytes in w, reads back len(r)
// bytes and stores them in r, and generates a stop condition on the bus.
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
var err error
if len(w) != 0 {
// send start/address for write
@@ -812,7 +812,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// WriteByte writes a single byte to the I2C bus.
func (i2c I2C) WriteByte(data byte) error {
func (i2c *I2C) WriteByte(data byte) error {
// Send data byte
i2c.Bus.DATA.Set(data)
@@ -837,7 +837,7 @@ func (i2c I2C) WriteByte(data byte) error {
}
// sendAddress sends the address and start signal
func (i2c I2C) sendAddress(address uint16, write bool) error {
func (i2c *I2C) sendAddress(address uint16, write bool) error {
data := (address << 1)
if !write {
data |= 1 // set read flag
@@ -857,7 +857,7 @@ func (i2c I2C) sendAddress(address uint16, write bool) error {
return nil
}
func (i2c I2C) signalStop() error {
func (i2c *I2C) signalStop() error {
i2c.Bus.CTRLB.SetBits(wireCmdStop << sam.SERCOM_I2CM_CTRLB_CMD_Pos) // Stop command
timeout := i2cTimeout
for i2c.Bus.SYNCBUSY.HasBits(sam.SERCOM_I2CM_SYNCBUSY_SYSOP) {
@@ -869,7 +869,7 @@ func (i2c I2C) signalStop() error {
return nil
}
func (i2c I2C) signalRead() error {
func (i2c *I2C) signalRead() error {
i2c.Bus.CTRLB.SetBits(wireCmdRead << sam.SERCOM_I2CM_CTRLB_CMD_Pos) // Read command
timeout := i2cTimeout
for i2c.Bus.SYNCBUSY.HasBits(sam.SERCOM_I2CM_SYNCBUSY_SYSOP) {
@@ -881,7 +881,7 @@ func (i2c I2C) signalRead() error {
return nil
}
func (i2c I2C) readByte() byte {
func (i2c *I2C) readByte() byte {
for !i2c.Bus.INTFLAG.HasBits(sam.SERCOM_I2CM_INTFLAG_SB) {
}
return byte(i2c.Bus.DATA.Get())
+78 -8
View File
@@ -1104,7 +1104,7 @@ const (
const i2cTimeout = 1000
// Configure is intended to setup the I2C interface.
func (i2c I2C) Configure(config I2CConfig) error {
func (i2c *I2C) Configure(config I2CConfig) error {
// Default I2C bus speed is 100 kHz.
if config.Frequency == 0 {
config.Frequency = TWI_FREQ_100KHZ
@@ -1163,7 +1163,7 @@ func (i2c I2C) Configure(config I2CConfig) error {
}
// SetBaudRate sets the communication speed for the I2C.
func (i2c I2C) SetBaudRate(br uint32) {
func (i2c *I2C) SetBaudRate(br uint32) {
// Synchronous arithmetic baudrate, via Adafruit SAMD51 implementation:
// sercom->I2CM.BAUD.bit.BAUD = SERCOM_FREQ_REF / ( 2 * baudrate) - 1 ;
baud := SERCOM_FREQ_REF/(2*br) - 1
@@ -1173,7 +1173,7 @@ func (i2c I2C) SetBaudRate(br uint32) {
// Tx does a single I2C transaction at the specified address.
// It clocks out the given address, writes the bytes in w, reads back len(r)
// bytes and stores them in r, and generates a stop condition on the bus.
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
var err error
if len(w) != 0 {
// send start/address for write
@@ -1250,7 +1250,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// WriteByte writes a single byte to the I2C bus.
func (i2c I2C) WriteByte(data byte) error {
func (i2c *I2C) WriteByte(data byte) error {
// Send data byte
i2c.Bus.DATA.Set(data)
@@ -1275,7 +1275,7 @@ func (i2c I2C) WriteByte(data byte) error {
}
// sendAddress sends the address and start signal
func (i2c I2C) sendAddress(address uint16, write bool) error {
func (i2c *I2C) sendAddress(address uint16, write bool) error {
data := (address << 1)
if !write {
data |= 1 // set read flag
@@ -1295,7 +1295,7 @@ func (i2c I2C) sendAddress(address uint16, write bool) error {
return nil
}
func (i2c I2C) signalStop() error {
func (i2c *I2C) signalStop() error {
i2c.Bus.CTRLB.SetBits(wireCmdStop << sam.SERCOM_I2CM_CTRLB_CMD_Pos) // Stop command
timeout := i2cTimeout
for i2c.Bus.SYNCBUSY.HasBits(sam.SERCOM_I2CM_SYNCBUSY_SYSOP) {
@@ -1307,7 +1307,7 @@ func (i2c I2C) signalStop() error {
return nil
}
func (i2c I2C) signalRead() error {
func (i2c *I2C) signalRead() error {
i2c.Bus.CTRLB.SetBits(wireCmdRead << sam.SERCOM_I2CM_CTRLB_CMD_Pos) // Read command
timeout := i2cTimeout
for i2c.Bus.SYNCBUSY.HasBits(sam.SERCOM_I2CM_SYNCBUSY_SYSOP) {
@@ -1319,7 +1319,7 @@ func (i2c I2C) signalRead() error {
return nil
}
func (i2c I2C) readByte() byte {
func (i2c *I2C) readByte() byte {
for !i2c.Bus.INTFLAG.HasBits(sam.SERCOM_I2CM_INTFLAG_SB) {
}
return byte(i2c.Bus.DATA.Get())
@@ -1560,6 +1560,76 @@ func (spi SPI) txrx(tx, rx []byte) {
rx[len(rx)-1] = byte(spi.Bus.DATA.Get())
}
// TxN handles read/write operation for SPI interface. The difference with Tx() is that
// it repeats the process n times.
//
func (spi SPI) TxN(w, r []byte, n int) error {
switch {
case w == nil:
// read only, so write zero and read a result.
spi.rxn(r, n)
case r == nil:
// write only
spi.txn(w, n)
default:
// write/read
if len(w) != len(r) {
return ErrTxInvalidSliceSize
}
spi.txrxn(w, r, n)
}
return nil
}
func (spi SPI) txn(tx []byte, n int) {
for i := 0; i < len(tx)*n; i++ {
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_DRE) {
}
spi.Bus.DATA.Set(uint32(tx[i%len(tx)]))
}
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_TXC) {
}
// read to clear RXC register
for spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) {
spi.Bus.DATA.Get()
}
}
func (spi SPI) rxn(rx []byte, n int) {
spi.Bus.DATA.Set(0)
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_DRE) {
}
for i := 1; i < len(rx)*n; i++ {
spi.Bus.DATA.Set(0)
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) {
}
rx[(i-1)%len(rx)] = byte(spi.Bus.DATA.Get())
}
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) {
}
rx[len(rx)-1] = byte(spi.Bus.DATA.Get())
}
func (spi SPI) txrxn(tx, rx []byte, n int) {
spi.Bus.DATA.Set(uint32(tx[0]))
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_DRE) {
}
for i := 1; i < len(rx)*n; i++ {
spi.Bus.DATA.Set(uint32(tx[i%len(rx)]))
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) {
}
rx[(i-1)%len(rx)] = byte(spi.Bus.DATA.Get())
}
for !spi.Bus.INTFLAG.HasBits(sam.SERCOM_SPIM_INTFLAG_RXC) {
}
rx[len(rx)-1] = byte(spi.Bus.DATA.Get())
}
// The QSPI peripheral on ATSAMD51 is only available on the following pins
const (
QSPI_SCK = PB10
-9
View File
@@ -1,9 +0,0 @@
// +build avr,attiny
package machine
// Tx is a dummy implementation. I2C has not been implemented for ATtiny
// devices.
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
return nil
}
-7
View File
@@ -141,10 +141,3 @@ func (a ADC) Get() uint16 {
return uint16(avr.ADCL.Get()) | uint16(avr.ADCH.Get())<<8
}
// I2C on AVR.
type I2C struct {
}
// I2C0 is the only I2C interface on most AVRs.
var I2C0 = I2C{}
+11 -6
View File
@@ -5,6 +5,7 @@ package machine
import (
"device/sifive"
"runtime/interrupt"
"unsafe"
)
func CPUFrequency() uint32 {
@@ -185,9 +186,13 @@ func (spi SPI) Transfer(w byte) (byte, error) {
// I2C on the FE310-G002.
type I2C struct {
Bus *sifive.I2C_Type
Bus sifive.I2C_Type
}
var (
I2C0 = (*I2C)(unsafe.Pointer(sifive.I2C0))
)
// I2CConfig is used to store config info for I2C.
type I2CConfig struct {
Frequency uint32
@@ -196,7 +201,7 @@ type I2CConfig struct {
}
// Configure is intended to setup the I2C interface.
func (i2c I2C) Configure(config I2CConfig) error {
func (i2c *I2C) Configure(config I2CConfig) error {
var i2cClockFrequency uint32 = 32000000
if config.Frequency == 0 {
config.Frequency = TWI_FREQ_100KHZ
@@ -228,7 +233,7 @@ func (i2c I2C) Configure(config I2CConfig) error {
// Tx does a single I2C transaction at the specified address.
// It clocks out the given address, writes the bytes in w, reads back len(r)
// bytes and stores them in r, and generates a stop condition on the bus.
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
var err error
if len(w) != 0 {
// send start/address for write
@@ -276,7 +281,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
}
// Writes a single byte to the I2C bus.
func (i2c I2C) writeByte(data byte) error {
func (i2c *I2C) writeByte(data byte) error {
// Send data byte
i2c.Bus.TXR_RXR.Set(uint32(data))
@@ -295,7 +300,7 @@ func (i2c I2C) writeByte(data byte) error {
}
// Reads a single byte from the I2C bus.
func (i2c I2C) readByte() byte {
func (i2c *I2C) readByte() byte {
i2c.Bus.CR_SR.Set(sifive.I2C_CR_RD)
// wait until transmission complete
@@ -306,7 +311,7 @@ func (i2c I2C) readByte() byte {
}
// Sends the address and start signal.
func (i2c I2C) sendAddress(address uint16, write bool) error {
func (i2c *I2C) sendAddress(address uint16, write bool) error {
data := (address << 1)
if !write {
data |= 1 // set read flag in transmit register
+3 -3
View File
@@ -6,7 +6,7 @@ package machine
var (
SPI0 = SPI{0}
I2C0 = I2C{0}
I2C0 = &I2C{0}
UART0 = UART{0}
)
@@ -115,13 +115,13 @@ type I2CConfig struct {
}
// Configure is intended to setup the I2C interface.
func (i2c I2C) Configure(config I2CConfig) error {
func (i2c *I2C) Configure(config I2CConfig) error {
i2cConfigure(i2c.Bus, config.SCL, config.SDA)
return nil
}
// Tx does a single I2C transaction at the specified address.
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
i2cTransfer(i2c.Bus, &w[0], len(w), &r[0], len(r))
// TODO: do something with the returned error code.
return nil
+11 -4
View File
@@ -7,6 +7,7 @@ import (
"device/riscv"
"errors"
"runtime/interrupt"
"unsafe"
)
func CPUFrequency() uint32 {
@@ -493,9 +494,15 @@ func (spi SPI) Transfer(w byte) (byte, error) {
// I2C on the K210.
type I2C struct {
Bus *kendryte.I2C_Type
Bus kendryte.I2C_Type
}
var (
I2C0 = (*I2C)(unsafe.Pointer(kendryte.I2C0))
I2C1 = (*I2C)(unsafe.Pointer(kendryte.I2C1))
I2C2 = (*I2C)(unsafe.Pointer(kendryte.I2C2))
)
// I2CConfig is used to store config info for I2C.
type I2CConfig struct {
Frequency uint32
@@ -504,7 +511,7 @@ type I2CConfig struct {
}
// Configure is intended to setup the I2C interface.
func (i2c I2C) Configure(config I2CConfig) error {
func (i2c *I2C) Configure(config I2CConfig) error {
if config.Frequency == 0 {
config.Frequency = TWI_FREQ_100KHZ
@@ -518,7 +525,7 @@ func (i2c I2C) Configure(config I2CConfig) error {
// Enable APB0 clock.
kendryte.SYSCTL.CLK_EN_CENT.SetBits(kendryte.SYSCTL_CLK_EN_CENT_APB0_CLK_EN)
switch i2c.Bus {
switch &i2c.Bus {
case kendryte.I2C0:
// Initialize I2C0 clock.
kendryte.SYSCTL.CLK_EN_PERI.SetBits(kendryte.SYSCTL_CLK_EN_PERI_I2C0_CLK_EN)
@@ -567,7 +574,7 @@ func (i2c I2C) Configure(config I2CConfig) error {
// Tx does a single I2C transaction at the specified address.
// It clocks out the given address, writes the bytes in w, reads back len(r)
// bytes and stores them in r, and generates a stop condition on the bus.
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
// Set peripheral address.
i2c.Bus.TAR.Set(uint32(addr))
// Enable controller.
+9 -8
View File
@@ -6,6 +6,7 @@ import (
"device/nrf"
"errors"
"runtime/interrupt"
"unsafe"
)
var (
@@ -203,13 +204,13 @@ func (uart *UART) handleInterrupt(interrupt.Interrupt) {
// I2C on the NRF.
type I2C struct {
Bus *nrf.TWI_Type
Bus nrf.TWI_Type
}
// There are 2 I2C interfaces on the NRF.
var (
I2C0 = I2C{Bus: nrf.TWI0}
I2C1 = I2C{Bus: nrf.TWI1}
I2C0 = (*I2C)(unsafe.Pointer(nrf.TWI0))
I2C1 = (*I2C)(unsafe.Pointer(nrf.TWI1))
)
// I2CConfig is used to store config info for I2C.
@@ -220,7 +221,7 @@ type I2CConfig struct {
}
// Configure is intended to setup the I2C interface.
func (i2c I2C) Configure(config I2CConfig) error {
func (i2c *I2C) Configure(config I2CConfig) error {
// Default I2C bus speed is 100 kHz.
if config.Frequency == 0 {
config.Frequency = TWI_FREQ_100KHZ
@@ -261,7 +262,7 @@ func (i2c I2C) Configure(config I2CConfig) error {
// Tx does a single I2C transaction at the specified address.
// It clocks out the given address, writes the bytes in w, reads back len(r)
// bytes and stores them in r, and generates a stop condition on the bus.
func (i2c I2C) Tx(addr uint16, w, r []byte) (err error) {
func (i2c *I2C) Tx(addr uint16, w, r []byte) (err error) {
i2c.Bus.ADDRESS.Set(uint32(addr))
if len(w) != 0 {
@@ -299,7 +300,7 @@ cleanUp:
// signalStop sends a stop signal when writing or tells the I2C peripheral that
// it must generate a stop condition after the next character is retrieved when
// reading.
func (i2c I2C) signalStop() {
func (i2c *I2C) signalStop() {
i2c.Bus.TASKS_STOP.Set(1)
for i2c.Bus.EVENTS_STOPPED.Get() == 0 {
}
@@ -307,7 +308,7 @@ func (i2c I2C) signalStop() {
}
// writeByte writes a single byte to the I2C bus.
func (i2c I2C) writeByte(data byte) error {
func (i2c *I2C) writeByte(data byte) error {
i2c.Bus.TXD.Set(uint32(data))
for i2c.Bus.EVENTS_TXDSENT.Get() == 0 {
if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 {
@@ -320,7 +321,7 @@ func (i2c I2C) writeByte(data byte) error {
}
// readByte reads a single byte from the I2C bus.
func (i2c I2C) readByte() (byte, error) {
func (i2c *I2C) readByte() (byte, error) {
for i2c.Bus.EVENTS_RXDREADY.Get() == 0 {
if e := i2c.Bus.EVENTS_ERROR.Get(); e != 0 {
i2c.Bus.EVENTS_ERROR.Set(0)
+1 -1
View File
@@ -24,7 +24,7 @@ func (uart UART) setPins(tx, rx Pin) {
nrf.UART0.PSELRXD.Set(uint32(rx))
}
func (i2c I2C) setPins(scl, sda Pin) {
func (i2c *I2C) setPins(scl, sda Pin) {
i2c.Bus.PSELSCL.Set(uint32(scl))
i2c.Bus.PSELSDA.Set(uint32(sda))
}
+1 -1
View File
@@ -56,7 +56,7 @@ func (uart UART) setPins(tx, rx Pin) {
nrf.UART0.PSELRXD.Set(uint32(rx))
}
func (i2c I2C) setPins(scl, sda Pin) {
func (i2c *I2C) setPins(scl, sda Pin) {
i2c.Bus.PSELSCL.Set(uint32(scl))
i2c.Bus.PSELSDA.Set(uint32(sda))
}
+1 -1
View File
@@ -76,7 +76,7 @@ func (uart UART) setPins(tx, rx Pin) {
nrf.UART0.PSEL.RXD.Set(uint32(rx))
}
func (i2c I2C) setPins(scl, sda Pin) {
func (i2c *I2C) setPins(scl, sda Pin) {
i2c.Bus.PSEL.SCL.Set(uint32(scl))
i2c.Bus.PSEL.SDA.Set(uint32(sda))
}
+1 -1
View File
@@ -72,7 +72,7 @@ func (uart UART) setPins(tx, rx Pin) {
nrf.UART0.PSEL.RXD.Set(uint32(rx))
}
func (i2c I2C) setPins(scl, sda Pin) {
func (i2c *I2C) setPins(scl, sda Pin) {
i2c.Bus.PSEL.SCL.Set(uint32(scl))
i2c.Bus.PSEL.SDA.Set(uint32(sda))
}
@@ -1,8 +1,9 @@
// +build stm32,!stm32f7x2,!stm32l5x2,!stm32l0
// +build stm32f4 stm32f1
package machine
// Peripheral abstraction layer for I2C on the stm32 family
// I2C implementation for 'older' STM32 MCUs, including the F1 and F4 series
// of MCUs.
import (
"device/stm32"
@@ -28,7 +29,7 @@ const (
flagMSL = 0x00100001
)
func (i2c I2C) hasFlag(flag uint32) bool {
func (i2c *I2C) hasFlag(flag uint32) bool {
const mask = 0x0000FFFF
if uint8(flag>>16) == 1 {
return i2c.Bus.SR1.HasBits(flag & mask)
@@ -37,18 +38,18 @@ func (i2c I2C) hasFlag(flag uint32) bool {
}
}
func (i2c I2C) clearFlag(flag uint32) {
func (i2c *I2C) clearFlag(flag uint32) {
const mask = 0x0000FFFF
i2c.Bus.SR1.Set(^(flag & mask))
}
// clearFlagADDR reads both status registers to clear any pending ADDR flags.
func (i2c I2C) clearFlagADDR() {
func (i2c *I2C) clearFlagADDR() {
i2c.Bus.SR1.Get()
i2c.Bus.SR2.Get()
}
func (i2c I2C) waitForFlag(flag uint32, set bool) bool {
func (i2c *I2C) waitForFlag(flag uint32, set bool) bool {
const tryMax = 10000
hasFlag := false
for i := 0; !hasFlag && i < tryMax; i++ {
@@ -57,7 +58,7 @@ func (i2c I2C) waitForFlag(flag uint32, set bool) bool {
return hasFlag
}
func (i2c I2C) waitForFlagOrError(flag uint32, set bool) bool {
func (i2c *I2C) waitForFlagOrError(flag uint32, set bool) bool {
const tryMax = 10000
hasFlag := false
for i := 0; !hasFlag && i < tryMax; i++ {
@@ -106,7 +107,7 @@ type I2CConfig struct {
}
// Configure is intended to setup the STM32 I2C interface.
func (i2c I2C) Configure(config I2CConfig) error {
func (i2c *I2C) Configure(config I2CConfig) error {
// The following is the required sequence in controller mode.
// 1. Program the peripheral input clock in I2C_CR2 Register in order to
@@ -156,7 +157,7 @@ func (i2c I2C) Configure(config I2CConfig) error {
return nil
}
func (i2c I2C) Tx(addr uint16, w, r []byte) error {
func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
if err := i2c.controllerTransmit(addr, w); nil != err {
return err
@@ -171,7 +172,7 @@ func (i2c I2C) Tx(addr uint16, w, r []byte) error {
return nil
}
func (i2c I2C) controllerTransmit(addr uint16, w []byte) error {
func (i2c *I2C) controllerTransmit(addr uint16, w []byte) error {
if !i2c.waitForFlag(flagBUSY, false) {
return errI2CBusReadyTimeout
@@ -223,7 +224,7 @@ func (i2c I2C) controllerTransmit(addr uint16, w []byte) error {
return nil
}
func (i2c I2C) controllerRequestWrite(addr uint16, option transferOption) error {
func (i2c *I2C) controllerRequestWrite(addr uint16, option transferOption) error {
if frameFirstAndLast == option || frameFirst == option || frameNoOption == option {
// generate start condition
@@ -249,7 +250,7 @@ func (i2c I2C) controllerRequestWrite(addr uint16, option transferOption) error
return nil
}
func (i2c I2C) controllerReceive(addr uint16, r []byte) error {
func (i2c *I2C) controllerReceive(addr uint16, r []byte) error {
if !i2c.waitForFlag(flagBUSY, false) {
return errI2CBusReadyTimeout
@@ -399,7 +400,7 @@ func (i2c I2C) controllerReceive(addr uint16, r []byte) error {
return nil
}
func (i2c I2C) controllerRequestRead(addr uint16, option transferOption) error {
func (i2c *I2C) controllerRequestRead(addr uint16, option transferOption) error {
// enable ACK
i2c.Bus.CR1.SetBits(stm32.I2C_CR1_ACK)
+347
View File
@@ -0,0 +1,347 @@
// +build stm32l5 stm32f7 stm32l4
package machine
import (
"device/stm32"
"unsafe"
)
//go:linkname ticks runtime.ticks
func ticks() int64
// I2C implementation for 'newer' STM32 MCUs, including the F7, L5 and L4
// series of MCUs.
//
// Currently, only 100KHz mode is supported
const (
flagBUSY = stm32.I2C_ISR_BUSY
flagTCR = stm32.I2C_ISR_TCR
flagRXNE = stm32.I2C_ISR_RXNE
flagSTOPF = stm32.I2C_ISR_STOPF
flagAF = stm32.I2C_ISR_NACKF
flagTXIS = stm32.I2C_ISR_TXIS
flagTXE = stm32.I2C_ISR_TXE
)
const (
MAX_NBYTE_SIZE = 255
TIMEOUT_TICKS = 100 // 100ms
I2C_NO_STARTSTOP = 0x0
I2C_GENERATE_START_WRITE = 0x80000000 | stm32.I2C_CR2_START
I2C_GENERATE_START_READ = 0x80000000 | stm32.I2C_CR2_START | stm32.I2C_CR2_RD_WRN
I2C_GENERATE_STOP = 0x80000000 | stm32.I2C_CR2_STOP
)
type I2C struct {
Bus *stm32.I2C_Type
AltFuncSelector uint8
}
// I2CConfig is used to store config info for I2C.
type I2CConfig struct {
SCL Pin
SDA Pin
}
func (i2c *I2C) Configure(config I2CConfig) error {
// disable I2C interface before any configuration changes
i2c.Bus.CR1.ClearBits(stm32.I2C_CR1_PE)
// enable clock for I2C
enableAltFuncClock(unsafe.Pointer(i2c.Bus))
// init pins
if config.SCL == 0 && config.SDA == 0 {
config.SCL = I2C0_SCL_PIN
config.SDA = I2C0_SDA_PIN
}
i2c.configurePins(config)
// Frequency range
i2c.Bus.TIMINGR.Set(i2c.getFreqRange())
// Disable Own Address1 before set the Own Address1 configuration
i2c.Bus.OAR1.ClearBits(stm32.I2C_OAR1_OA1EN)
// 7 bit addressing, no self address
i2c.Bus.OAR1.Set(stm32.I2C_OAR1_OA1EN)
// Enable the AUTOEND by default, and enable NACK (should be disable only during Slave process
i2c.Bus.CR2.Set(stm32.I2C_CR2_AUTOEND | stm32.I2C_CR2_NACK)
// Disable Own Address2 / Dual Addressing
i2c.Bus.OAR2.Set(0)
// Disable Generalcall and NoStretch, Enable peripheral
i2c.Bus.CR1.Set(stm32.I2C_CR1_PE)
return nil
}
func (i2c *I2C) Tx(addr uint16, w, r []byte) error {
if len(w) > 0 {
if err := i2c.controllerTransmit(addr, w); nil != err {
return err
}
}
if len(r) > 0 {
if err := i2c.controllerReceive(addr, r); nil != err {
return err
}
}
return nil
}
func (i2c *I2C) configurePins(config I2CConfig) {
config.SCL.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSCL}, i2c.AltFuncSelector)
config.SDA.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSDA}, i2c.AltFuncSelector)
}
func (i2c *I2C) controllerTransmit(addr uint16, w []byte) error {
start := ticks()
if !i2c.waitOnFlagUntilTimeout(flagBUSY, false, start) {
return errI2CBusReadyTimeout
}
pos := 0
xferCount := len(w)
xferSize := uint8(xferCount)
if xferCount > MAX_NBYTE_SIZE {
// Large write, indicate reload
xferSize = MAX_NBYTE_SIZE
i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_GENERATE_START_WRITE)
} else {
// Small write, auto-end
i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_GENERATE_START_WRITE)
}
for xferCount > 0 {
if !i2c.waitOnTXISFlagUntilTimeout(start) {
return errI2CWriteTimeout
}
i2c.Bus.TXDR.Set(uint32(w[pos]))
pos++
xferCount--
xferSize--
// If we've written the last byte of this chunk
if xferCount != 0 && xferSize == 0 {
// Wait for Transfer Complete Reload to be flagged
if !i2c.waitOnFlagUntilTimeout(flagTCR, true, start) {
return errI2CWriteTimeout
}
if xferCount > MAX_NBYTE_SIZE {
// Large write remaining, indicate reload
xferSize = MAX_NBYTE_SIZE
i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_NO_STARTSTOP)
} else {
// Small write, auto-end
xferSize = uint8(xferCount)
i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_NO_STARTSTOP)
}
}
}
if !i2c.waitOnStopFlagUntilTimeout(start) {
return errI2CWriteTimeout
}
i2c.clearFlag(stm32.I2C_ISR_STOPF)
i2c.resetCR2()
return nil
}
func (i2c *I2C) controllerReceive(addr uint16, r []byte) error {
start := ticks()
if !i2c.waitOnFlagUntilTimeout(flagBUSY, false, start) {
return errI2CBusReadyTimeout
}
pos := 0
xferCount := len(r)
xferSize := uint8(xferCount)
if xferCount > MAX_NBYTE_SIZE {
// Large read, indicate reload
xferSize = MAX_NBYTE_SIZE
i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_GENERATE_START_READ)
} else {
// Small read, auto-end
i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_GENERATE_START_READ)
}
for xferCount > 0 {
if !i2c.waitOnRXNEFlagUntilTimeout(start) {
return errI2CWriteTimeout
}
r[pos] = uint8(i2c.Bus.RXDR.Get())
pos++
xferCount--
xferSize--
// If we've read the last byte of this chunk
if xferCount != 0 && xferSize == 0 {
// Wait for Transfer Complete Reload to be flagged
if !i2c.waitOnFlagUntilTimeout(flagTCR, true, start) {
return errI2CWriteTimeout
}
if xferCount > MAX_NBYTE_SIZE {
// Large read remaining, indicate reload
xferSize = MAX_NBYTE_SIZE
i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_RELOAD, I2C_NO_STARTSTOP)
} else {
// Small read, auto-end
xferSize = uint8(xferCount)
i2c.transferConfig(addr, xferSize, stm32.I2C_CR2_AUTOEND, I2C_NO_STARTSTOP)
}
}
}
if !i2c.waitOnStopFlagUntilTimeout(start) {
return errI2CWriteTimeout
}
i2c.clearFlag(stm32.I2C_ISR_STOPF)
i2c.resetCR2()
return nil
}
func (i2c *I2C) waitOnFlagUntilTimeout(flag uint32, set bool, startTicks int64) bool {
for i2c.hasFlag(flag) != set {
if (ticks() - startTicks) > TIMEOUT_TICKS {
return false
}
}
return true
}
func (i2c *I2C) waitOnRXNEFlagUntilTimeout(startTicks int64) bool {
for !i2c.hasFlag(flagRXNE) {
if i2c.isAcknowledgeFailed(startTicks) {
return false
}
if i2c.hasFlag(flagSTOPF) {
i2c.clearFlag(flagSTOPF)
i2c.resetCR2()
return false
}
if (ticks() - startTicks) > TIMEOUT_TICKS {
return false
}
}
return true
}
func (i2c *I2C) waitOnTXISFlagUntilTimeout(startTicks int64) bool {
for !i2c.hasFlag(flagTXIS) {
if i2c.isAcknowledgeFailed(startTicks) {
return false
}
if (ticks() - startTicks) > TIMEOUT_TICKS {
return false
}
}
return true
}
func (i2c *I2C) waitOnStopFlagUntilTimeout(startTicks int64) bool {
for !i2c.hasFlag(flagSTOPF) {
if i2c.isAcknowledgeFailed(startTicks) {
return false
}
if (ticks() - startTicks) > TIMEOUT_TICKS {
return false
}
}
return true
}
func (i2c *I2C) isAcknowledgeFailed(startTicks int64) bool {
if i2c.hasFlag(flagAF) {
// Wait until STOP Flag is reset
// AutoEnd should be initiate after AF
for !i2c.hasFlag(flagSTOPF) {
if (ticks() - startTicks) > TIMEOUT_TICKS {
return true
}
}
i2c.clearFlag(flagAF)
i2c.clearFlag(flagSTOPF)
i2c.flushTXDR()
i2c.resetCR2()
return true
}
return false
}
func (i2c *I2C) flushTXDR() {
// If a pending TXIS flag is set, write a dummy data in TXDR to clear it
if i2c.hasFlag(flagTXIS) {
i2c.Bus.TXDR.Set(0)
}
// Flush TX register if not empty
if !i2c.hasFlag(flagTXE) {
i2c.clearFlag(flagTXE)
}
}
func (i2c *I2C) resetCR2() {
i2c.Bus.CR2.ClearBits(stm32.I2C_CR2_SADD_Msk |
stm32.I2C_CR2_HEAD10R_Msk |
stm32.I2C_CR2_NBYTES_Msk |
stm32.I2C_CR2_RELOAD_Msk |
stm32.I2C_CR2_RD_WRN_Msk)
}
func (i2c *I2C) transferConfig(addr uint16, size uint8, mode uint32, request uint32) {
mask := uint32(stm32.I2C_CR2_SADD_Msk |
stm32.I2C_CR2_NBYTES_Msk |
stm32.I2C_CR2_RELOAD_Msk |
stm32.I2C_CR2_AUTOEND_Msk |
(stm32.I2C_CR2_RD_WRN & uint32(request>>(31-stm32.I2C_CR2_RD_WRN_Pos))) |
stm32.I2C_CR2_START_Msk |
stm32.I2C_CR2_STOP_Msk)
value := (uint32(addr<<1) & stm32.I2C_CR2_SADD_Msk) |
((uint32(size) << stm32.I2C_CR2_NBYTES_Pos) & stm32.I2C_CR2_NBYTES_Msk) |
mode | request
i2c.Bus.CR2.ReplaceBits(value, mask, 0)
}
func (i2c *I2C) hasFlag(flag uint32) bool {
return i2c.Bus.ISR.HasBits(flag)
}
func (i2c *I2C) clearFlag(flag uint32) {
if flag == stm32.I2C_ISR_TXE {
i2c.Bus.ISR.SetBits(flag)
} else {
i2c.Bus.ICR.SetBits(flag)
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
// +build stm32,!stm32f7x2,!stm32l5x2
// +build stm32,!stm32f7x2,!stm32l5x2,!stm32l4x2
package machine
+5 -4
View File
@@ -13,10 +13,11 @@ import (
// UART representation
type UART struct {
Buffer *RingBuffer
Bus *stm32.USART_Type
Interrupt interrupt.Interrupt
AltFuncSelector uint8
Buffer *RingBuffer
Bus *stm32.USART_Type
Interrupt interrupt.Interrupt
TxAltFuncSelector uint8
RxAltFuncSelector uint8
// Registers specific to the chip
rxReg *volatile.Register32
+5 -5
View File
@@ -201,7 +201,7 @@ func (spi SPI) configurePins(config SPIConfig) {
// Since the first interface is named I2C1, both I2C0 and I2C1 refer to I2C1.
// TODO: implement I2C2.
var (
I2C1 = I2C{Bus: stm32.I2C1}
I2C1 = (*I2C)(unsafe.Pointer(stm32.I2C1))
I2C0 = I2C1
)
@@ -209,7 +209,7 @@ type I2C struct {
Bus *stm32.I2C_Type
}
func (i2c I2C) configurePins(config I2CConfig) {
func (i2c *I2C) configurePins(config I2CConfig) {
if config.SDA == PB9 {
// use alternate I2C1 pins PB8/PB9 via AFIO mapping
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_AFIOEN)
@@ -220,7 +220,7 @@ func (i2c I2C) configurePins(config I2CConfig) {
config.SCL.Configure(PinConfig{Mode: PinOutput50MHz + PinOutputModeAltOpenDrain})
}
func (i2c I2C) getFreqRange(config I2CConfig) uint32 {
func (i2c *I2C) getFreqRange(config I2CConfig) uint32 {
// pclk1 clock speed is main frequency divided by PCLK1 prescaler (div 2)
pclk1 := CPUFrequency() / 2
@@ -229,7 +229,7 @@ func (i2c I2C) getFreqRange(config I2CConfig) uint32 {
return pclk1 / 1000000
}
func (i2c I2C) getRiseTime(config I2CConfig) uint32 {
func (i2c *I2C) getRiseTime(config I2CConfig) uint32 {
// These bits must be programmed with the maximum SCL rise time given in the
// I2C bus specification, incremented by 1.
// For instance: in Sm mode, the maximum allowed SCL rise time is 1000 ns.
@@ -245,7 +245,7 @@ func (i2c I2C) getRiseTime(config I2CConfig) uint32 {
return (freqRange + 1) << stm32.I2C_TRISE_TRISE_Pos
}
func (i2c I2C) getSpeed(config I2CConfig) uint32 {
func (i2c *I2C) getSpeed(config I2CConfig) uint32 {
ccr := func(pclk uint32, freq uint32, coeff uint32) uint32 {
return (((pclk - 1) / (freq * coeff)) + 1) & stm32.I2C_CCR_CCR_Msk
}
+6 -6
View File
@@ -37,8 +37,8 @@ const (
func (uart *UART) configurePins(config UARTConfig) {
// enable the alternate functions on the TX and RX pins
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector)
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector)
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
}
func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 {
@@ -116,12 +116,12 @@ type I2C struct {
AltFuncSelector uint8
}
func (i2c I2C) configurePins(config I2CConfig) {
func (i2c *I2C) configurePins(config I2CConfig) {
config.SCL.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSCL}, i2c.AltFuncSelector)
config.SDA.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSDA}, i2c.AltFuncSelector)
}
func (i2c I2C) getFreqRange(config I2CConfig) uint32 {
func (i2c *I2C) getFreqRange(config I2CConfig) uint32 {
// all I2C interfaces are on APB1 (42 MHz)
clock := CPUFrequency() / 4
// convert to MHz
@@ -139,7 +139,7 @@ func (i2c I2C) getFreqRange(config I2CConfig) uint32 {
return clock << stm32.I2C_CR2_FREQ_Pos
}
func (i2c I2C) getRiseTime(config I2CConfig) uint32 {
func (i2c *I2C) getRiseTime(config I2CConfig) uint32 {
// These bits must be programmed with the maximum SCL rise time given in the
// I2C bus specification, incremented by 1.
// For instance: in Sm mode, the maximum allowed SCL rise time is 1000 ns.
@@ -155,7 +155,7 @@ func (i2c I2C) getRiseTime(config I2CConfig) uint32 {
return (freqRange + 1) << stm32.I2C_TRISE_TRISE_Pos
}
func (i2c I2C) getSpeed(config I2CConfig) uint32 {
func (i2c *I2C) getSpeed(config I2CConfig) uint32 {
ccr := func(pclk uint32, freq uint32, coeff uint32) uint32 {
return (((pclk - 1) / (freq * coeff)) + 1) & stm32.I2C_CCR_CCR_Msk
}
+6 -6
View File
@@ -37,8 +37,8 @@ const (
// Configure the UART.
func (uart *UART) configurePins(config UARTConfig) {
// enable the alternate functions on the TX and RX pins
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector)
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector)
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
}
// UART baudrate calc based on the bus and clockspeed
@@ -128,12 +128,12 @@ type I2C struct {
AltFuncSelector uint8
}
func (i2c I2C) configurePins(config I2CConfig) {
func (i2c *I2C) configurePins(config I2CConfig) {
config.SCL.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSCL}, i2c.AltFuncSelector)
config.SDA.ConfigureAltFunc(PinConfig{Mode: PinModeI2CSDA}, i2c.AltFuncSelector)
}
func (i2c I2C) getFreqRange(config I2CConfig) uint32 {
func (i2c *I2C) getFreqRange(config I2CConfig) uint32 {
// all I2C interfaces are on APB1 (42 MHz)
clock := CPUFrequency() / 4
// convert to MHz
@@ -151,7 +151,7 @@ func (i2c I2C) getFreqRange(config I2CConfig) uint32 {
return clock << stm32.I2C_CR2_FREQ_Pos
}
func (i2c I2C) getRiseTime(config I2CConfig) uint32 {
func (i2c *I2C) getRiseTime(config I2CConfig) uint32 {
// These bits must be programmed with the maximum SCL rise time given in the
// I2C bus specification, incremented by 1.
// For instance: in Sm mode, the maximum allowed SCL rise time is 1000 ns.
@@ -167,7 +167,7 @@ func (i2c I2C) getRiseTime(config I2CConfig) uint32 {
return (freqRange + 1) << stm32.I2C_TRISE_TRISE_Pos
}
func (i2c I2C) getSpeed(config I2CConfig) uint32 {
func (i2c *I2C) getSpeed(config I2CConfig) uint32 {
ccr := func(pclk uint32, freq uint32, coeff uint32) uint32 {
return (((pclk - 1) / (freq * coeff)) + 1) & stm32.I2C_CCR_CCR_Msk
}
+12 -2
View File
@@ -17,8 +17,8 @@ func CPUFrequency() uint32 {
// Configure the UART.
func (uart *UART) configurePins(config UARTConfig) {
// enable the alternate functions on the TX and RX pins
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector)
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector)
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
}
// UART baudrate calc based on the bus and clockspeed
@@ -41,3 +41,13 @@ func (uart *UART) setRegisters() {
uart.statusReg = &uart.Bus.ISR
uart.txEmptyFlag = stm32.USART_ISR_TXE
}
//---------- I2C related code
// Gets the value for TIMINGR register
func (i2c *I2C) getFreqRange() uint32 {
// This is a 'magic' value calculated by STM32CubeMX
// for 27MHz PCLK1 (216MHz CPU Freq / 8).
// TODO: Do calculations based on PCLK1
return 0x00606A9B
}
+2 -2
View File
@@ -191,8 +191,8 @@ func enableAltFuncClock(bus unsafe.Pointer) {
// Configure the UART.
func (uart UART) configurePins(config UARTConfig) {
// enable the alternate functions on the TX and RX pins
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector)
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector)
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
}
// UART baudrate calc based on the bus and clockspeed
+184
View File
@@ -0,0 +1,184 @@
// +build stm32l4
package machine
import (
"device/stm32"
"unsafe"
)
// Peripheral abstraction layer for the stm32l4
const (
PA0 = portA + 0
PA1 = portA + 1
PA2 = portA + 2
PA3 = portA + 3
PA4 = portA + 4
PA5 = portA + 5
PA6 = portA + 6
PA7 = portA + 7
PA8 = portA + 8
PA9 = portA + 9
PA10 = portA + 10
PA11 = portA + 11
PA12 = portA + 12
PA13 = portA + 13
PA14 = portA + 14
PA15 = portA + 15
PB0 = portB + 0
PB1 = portB + 1
PB2 = portB + 2
PB3 = portB + 3
PB4 = portB + 4
PB5 = portB + 5
PB6 = portB + 6
PB7 = portB + 7
PB8 = portB + 8
PB9 = portB + 9
PB10 = portB + 10
PB11 = portB + 11
PB12 = portB + 12
PB13 = portB + 13
PB14 = portB + 14
PB15 = portB + 15
PC0 = portC + 0
PC1 = portC + 1
PC2 = portC + 2
PC3 = portC + 3
PC4 = portC + 4
PC5 = portC + 5
PC6 = portC + 6
PC7 = portC + 7
PC8 = portC + 8
PC9 = portC + 9
PC10 = portC + 10
PC11 = portC + 11
PC12 = portC + 12
PC13 = portC + 13
PC14 = portC + 14
PC15 = portC + 15
PD0 = portD + 0
PD1 = portD + 1
PD2 = portD + 2
PD3 = portD + 3
PD4 = portD + 4
PD5 = portD + 5
PD6 = portD + 6
PD7 = portD + 7
PD8 = portD + 8
PD9 = portD + 9
PD10 = portD + 10
PD11 = portD + 11
PD12 = portD + 12
PD13 = portD + 13
PD14 = portD + 14
PD15 = portD + 15
PE0 = portE + 0
PE1 = portE + 1
PE2 = portE + 2
PE3 = portE + 3
PE4 = portE + 4
PE5 = portE + 5
PE6 = portE + 6
PE7 = portE + 7
PE8 = portE + 8
PE9 = portE + 9
PE10 = portE + 10
PE11 = portE + 11
PE12 = portE + 12
PE13 = portE + 13
PE14 = portE + 14
PE15 = portE + 15
)
func (p Pin) getPort() *stm32.GPIO_Type {
switch p / 16 {
case 0:
return stm32.GPIOA
case 1:
return stm32.GPIOB
case 2:
return stm32.GPIOC
case 3:
return stm32.GPIOD
case 4:
return stm32.GPIOE
default:
panic("machine: unknown port")
}
}
// enableClock enables the clock for this desired GPIO port.
func (p Pin) enableClock() {
switch p / 16 {
case 0:
stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOAEN)
case 1:
stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOBEN)
case 2:
stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOCEN)
case 3:
stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIODEN)
case 4:
stm32.RCC.AHB2ENR.SetBits(stm32.RCC_AHB2ENR_GPIOEEN)
default:
panic("machine: unknown port")
}
}
// Enable peripheral clock
func enableAltFuncClock(bus unsafe.Pointer) {
switch bus {
case unsafe.Pointer(stm32.PWR): // Power interface clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_PWREN)
case unsafe.Pointer(stm32.I2C3): // I2C3 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_I2C3EN)
case unsafe.Pointer(stm32.I2C2): // I2C2 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_I2C2EN)
case unsafe.Pointer(stm32.I2C1): // I2C1 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_I2C1EN)
case unsafe.Pointer(stm32.UART4): // UART4 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_UART4EN)
case unsafe.Pointer(stm32.USART3): // USART3 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_USART3EN)
case unsafe.Pointer(stm32.USART2): // USART2 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_USART2EN)
case unsafe.Pointer(stm32.SPI3): // SPI3 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_SPI3EN)
case unsafe.Pointer(stm32.SPI2): // SPI2 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_SPI2EN)
case unsafe.Pointer(stm32.WWDG): // Window watchdog clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_WWDGEN)
case unsafe.Pointer(stm32.TIM7): // TIM7 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM7EN)
case unsafe.Pointer(stm32.TIM6): // TIM6 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM6EN)
case unsafe.Pointer(stm32.TIM3): // TIM3 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM3EN)
case unsafe.Pointer(stm32.TIM2): // TIM2 clock enable
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_TIM2EN)
case unsafe.Pointer(stm32.LPTIM2): // LPTIM2 clock enable
stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_LPTIM2EN)
case unsafe.Pointer(stm32.I2C4): // I2C4 clock enable
stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_I2C4EN)
case unsafe.Pointer(stm32.LPUART1): // LPUART1 clock enable
stm32.RCC.APB1ENR2.SetBits(stm32.RCC_APB1ENR2_LPUART1EN)
case unsafe.Pointer(stm32.TIM16): // TIM16 clock enable
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM16EN)
case unsafe.Pointer(stm32.TIM15): // TIM15 clock enable
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM15EN)
case unsafe.Pointer(stm32.SYSCFG): // System configuration controller clock enable
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SYSCFGEN)
case unsafe.Pointer(stm32.SPI1): // SPI1 clock enable
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_SPI1EN)
case unsafe.Pointer(stm32.USART1): // USART1 clock enable
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_USART1EN)
case unsafe.Pointer(stm32.TIM1): // TIM1 clock enable
stm32.RCC.APB2ENR.SetBits(stm32.RCC_APB2ENR_TIM1EN)
}
}
+46
View File
@@ -0,0 +1,46 @@
// +build stm32l4x2
package machine
// Peripheral abstraction layer for the stm32l4x2
import (
"device/stm32"
)
func CPUFrequency() uint32 {
return 80000000
}
//---------- UART related code
// Configure the UART.
func (uart *UART) configurePins(config UARTConfig) {
// enable the alternate functions on the TX and RX pins
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector)
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
}
// UART baudrate calc based on the bus and clockspeed
// NOTE: keep this in sync with the runtime/runtime_stm32l5x2.go clock init code
func (uart *UART) getBaudRateDivisor(baudRate uint32) uint32 {
return (CPUFrequency() / baudRate)
}
// Register names vary by ST processor, these are for STM L5
func (uart *UART) setRegisters() {
uart.rxReg = &uart.Bus.RDR
uart.txReg = &uart.Bus.TDR
uart.statusReg = &uart.Bus.ISR
uart.txEmptyFlag = stm32.USART_ISR_TXE
}
//---------- I2C related code
// Gets the value for TIMINGR register
func (i2c *I2C) getFreqRange() uint32 {
// This is a 'magic' value calculated by STM32CubeMX
// for 80MHz PCLK1.
// TODO: Do calculations based on PCLK1
return 0x10909CEC
}
+12 -2
View File
@@ -22,8 +22,8 @@ func (uart *UART) configurePins(config UARTConfig) {
}
// enable the alternate functions on the TX and RX pins
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector)
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.TxAltFuncSelector)
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
}
// UART baudrate calc based on the bus and clockspeed
@@ -39,3 +39,13 @@ func (uart *UART) setRegisters() {
uart.statusReg = &uart.Bus.ISR
uart.txEmptyFlag = stm32.USART_ISR_TXE
}
//---------- I2C related code
// Gets the value for TIMINGR register
func (i2c *I2C) getFreqRange() uint32 {
// This is a 'magic' value calculated by STM32CubeMX
// for 110MHz PCLK1.
// TODO: Do calculations based on PCLK1
return 0x40505681
}
+1 -1
View File
@@ -1,4 +1,4 @@
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2 fe310 k210 atmega
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2,!stm32l4x2 fe310 k210 atmega
package machine
+39 -3
View File
@@ -2,6 +2,7 @@ package os
import (
"errors"
"syscall"
)
var (
@@ -17,9 +18,8 @@ var (
ErrExist = errors.New("file exists")
)
func IsPermission(err error) bool {
return err == ErrPermission
}
// The following code is copied from the official implementation.
// https://github.com/golang/go/blob/4ce6a8e89668b87dce67e2f55802903d6eb9110a/src/os/error.go#L65-L104
func NewSyscallError(syscall string, err error) error {
if err == nil {
@@ -37,3 +37,39 @@ type SyscallError struct {
func (e *SyscallError) Error() string { return e.Syscall + ": " + e.Err.Error() }
func (e *SyscallError) Unwrap() error { return e.Err }
func IsExist(err error) bool {
return underlyingErrorIs(err, ErrExist)
}
func IsNotExist(err error) bool {
return underlyingErrorIs(err, ErrNotExist)
}
func IsPermission(err error) bool {
return underlyingErrorIs(err, ErrPermission)
}
func underlyingErrorIs(err, target error) bool {
// Note that this function is not errors.Is:
// underlyingError only unwraps the specific error-wrapping types
// that it historically did, not all errors implementing Unwrap().
err = underlyingError(err)
if err == target {
return true
}
// To preserve prior behavior, only examine syscall errors.
e, ok := err.(syscall.Errno)
return ok && e.Is(target)
}
// underlyingError returns the underlying error for known os error types.
func underlyingError(err error) error {
switch err := err.(type) {
case *PathError:
return err.Err
case *SyscallError:
return err.Err
}
return err
}
+10 -61
View File
@@ -6,6 +6,7 @@
package os
import (
"io"
"syscall"
)
@@ -76,7 +77,7 @@ func Create(name string) (*File, error) {
// read and any error encountered. At end of file, Read returns 0, io.EOF.
func (f *File) Read(b []byte) (n int, err error) {
n, err = f.handle.Read(b)
if err != nil {
if err != nil && err != io.EOF {
err = &PathError{"read", f.name, err}
}
return
@@ -155,59 +156,17 @@ func (e *PathError) Error() string {
return e.Op + " " + e.Path + ": " + e.Err.Error()
}
type FileMode uint32
// Mode constants, copied from the mainline Go source
// https://github.com/golang/go/blob/4ce6a8e89668b87dce67e2f55802903d6eb9110a/src/os/types.go#L35-L63
const (
// The single letters are the abbreviations used by the String method's formatting.
ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory
ModeAppend // a: append-only
ModeExclusive // l: exclusive use
ModeTemporary // T: temporary file; Plan 9 only
ModeSymlink // L: symbolic link
ModeDevice // D: device file
ModeNamedPipe // p: named pipe (FIFO)
ModeSocket // S: Unix domain socket
ModeSetuid // u: setuid
ModeSetgid // g: setgid
ModeCharDevice // c: Unix character device, when ModeDevice is set
ModeSticky // t: sticky
ModeIrregular // ?: non-regular file; nothing else is known about this file
// Mask for the type bits. For regular files, none will be set.
ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice | ModeIrregular
ModePerm FileMode = 0777 // Unix permission bits
O_RDONLY int = syscall.O_RDONLY
O_WRONLY int = syscall.O_WRONLY
O_RDWR int = syscall.O_RDWR
O_APPEND int = syscall.O_APPEND
O_CREATE int = syscall.O_CREAT
O_EXCL int = syscall.O_EXCL
O_SYNC int = syscall.O_SYNC
O_TRUNC int = syscall.O_TRUNC
)
// IsDir is a stub, always returning false
func (m FileMode) IsDir() bool {
return false
}
// Stub constants
const (
O_RDONLY int = 1
O_WRONLY int = 2
O_RDWR int = 4
O_APPEND int = 8
O_CREATE int = 16
O_EXCL int = 32
O_SYNC int = 64
O_TRUNC int = 128
)
// A FileInfo describes a file and is returned by Stat and Lstat.
type FileInfo interface {
Name() string // base name of the file
Size() int64 // length in bytes for regular files; system-dependent for others
Mode() FileMode // file mode bits
// TODO ModTime() time.Time // modification time
IsDir() bool // abbreviation for Mode().IsDir()
Sys() interface{} // underlying data source (can return nil)
}
// Stat is a stub, not yet implemented
func Stat(name string) (FileInfo, error) {
return nil, &PathError{"stat", name, ErrNotImplemented}
@@ -233,16 +192,6 @@ func TempDir() string {
return "/tmp"
}
// IsExist is a stub (for now), always returning false
func IsExist(err error) bool {
return false
}
// IsNotExist is a stub (for now), always returning false
func IsNotExist(err error) bool {
return false
}
// Getpid is a stub (for now), always returning 1
func Getpid() int {
return 1
+81
View File
@@ -0,0 +1,81 @@
// +build go1.16
package os
import (
"io"
"io/fs"
)
type (
DirEntry = fs.DirEntry
FileMode = fs.FileMode
FileInfo = fs.FileInfo
)
func (f *File) ReadDir(n int) ([]DirEntry, error) {
return nil, &PathError{"ReadDir", f.name, ErrNotImplemented}
}
// The followings are copied from Go 1.16 official implementation:
// https://github.com/golang/go/blob/go1.16/src/os/file.go
// ReadFile reads the named file and returns the contents.
// A successful call returns err == nil, not err == EOF.
// Because ReadFile reads the whole file, it does not treat an EOF from Read
// as an error to be reported.
func ReadFile(name string) ([]byte, error) {
f, err := Open(name)
if err != nil {
return nil, err
}
defer f.Close()
var size int
if info, err := f.Stat(); err == nil {
size64 := info.Size()
if int64(int(size64)) == size64 {
size = int(size64)
}
}
size++ // one byte for final read at EOF
// If a file claims a small size, read at least 512 bytes.
// In particular, files in Linux's /proc claim size 0 but
// then do not work right if read in small pieces,
// so an initial read of 1 byte would not work correctly.
if size < 512 {
size = 512
}
data := make([]byte, 0, size)
for {
if len(data) >= cap(data) {
d := append(data[:cap(data)], 0)
data = d[:len(data)]
}
n, err := f.Read(data[len(data):cap(data)])
data = data[:len(data)+n]
if err != nil {
if err == io.EOF {
err = nil
}
return data, err
}
}
}
// WriteFile writes data to the named file, creating it if necessary.
// If the file does not exist, WriteFile creates it with permissions perm (before umask);
// otherwise WriteFile truncates it before writing, without changing permissions.
func WriteFile(name string, data []byte, perm FileMode) error {
f, err := OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, perm)
if err != nil {
return err
}
_, err = f.Write(data)
if err1 := f.Close(); err1 != nil && err == nil {
err = err1
}
return err
}
+46
View File
@@ -0,0 +1,46 @@
// +build !go1.16
package os
import "time"
// A FileInfo describes a file and is returned by Stat and Lstat.
type FileInfo interface {
Name() string // base name of the file
Size() int64 // length in bytes for regular files; system-dependent for others
Mode() FileMode // file mode bits
ModTime() time.Time // modification time
IsDir() bool // abbreviation for Mode().IsDir()
Sys() interface{} // underlying data source (can return nil)
}
type FileMode uint32
// Mode constants, copied from the mainline Go source
// https://github.com/golang/go/blob/4ce6a8e89668b87dce67e2f55802903d6eb9110a/src/os/types.go#L35-L63
const (
// The single letters are the abbreviations used by the String method's formatting.
ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory
ModeAppend // a: append-only
ModeExclusive // l: exclusive use
ModeTemporary // T: temporary file; Plan 9 only
ModeSymlink // L: symbolic link
ModeDevice // D: device file
ModeNamedPipe // p: named pipe (FIFO)
ModeSocket // S: Unix domain socket
ModeSetuid // u: setuid
ModeSetgid // g: setgid
ModeCharDevice // c: Unix character device, when ModeDevice is set
ModeSticky // t: sticky
ModeIrregular // ?: non-regular file; nothing else is known about this file
// Mask for the type bits. For regular files, none will be set.
ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice | ModeIrregular
ModePerm FileMode = 0777 // Unix permission bits
)
// IsDir is a stub, always returning false
func (m FileMode) IsDir() bool {
return false
}
+1 -1
View File
@@ -1,4 +1,4 @@
// +build baremetal wasm
// +build baremetal wasm,!wasi
package os
+5 -1
View File
@@ -1,8 +1,9 @@
// +build darwin linux,!baremetal,!wasi freebsd,!baremetal
// +build darwin linux,!baremetal freebsd,!baremetal
package os
import (
"io"
"syscall"
)
@@ -77,6 +78,9 @@ type unixFileHandle uintptr
func (f unixFileHandle) Read(b []byte) (n int, err error) {
n, err = syscall.Read(int(f), b)
err = handleSyscallError(err)
if n == 0 && err == nil {
err = io.EOF
}
return
}
+1 -1
View File
@@ -21,7 +21,7 @@ func Swapper(slice interface{}) func(i, j int) {
return func(i, j int) {}
}
typ := v.Type().Elem()
typ := v.typecode.Elem()
size := typ.Size()
header := (*SliceHeader)(v.value)
+274 -47
View File
@@ -122,30 +122,218 @@ func (k Kind) String() string {
}
// basicType returns a new Type for this kind if Kind is a basic type.
func (k Kind) basicType() Type {
return Type(k << 1)
func (k Kind) basicType() rawType {
return rawType(k << 1)
}
// The following Type type has been copied almost entirely from
// https://github.com/golang/go/blob/go1.15/src/reflect/type.go#L27-L212.
// Some methods have been commented out as they haven't yet been implemented.
// Type is the representation of a Go type.
//
// Not all methods apply to all kinds of types. Restrictions,
// if any, are noted in the documentation for each method.
// Use the Kind method to find out the kind of type before
// calling kind-specific methods. Calling a method
// inappropriate to the kind of type causes a run-time panic.
//
// Type values are comparable, such as with the == operator,
// so they can be used as map keys.
// Two Type values are equal if they represent identical types.
type Type interface {
// Methods applicable to all types.
// Align returns the alignment in bytes of a value of
// this type when allocated in memory.
Align() int
// FieldAlign returns the alignment in bytes of a value of
// this type when used as a field in a struct.
FieldAlign() int
// Method returns the i'th method in the type's method set.
// It panics if i is not in the range [0, NumMethod()).
//
// For a non-interface type T or *T, the returned Method's Type and Func
// fields describe a function whose first argument is the receiver.
//
// For an interface type, the returned Method's Type field gives the
// method signature, without a receiver, and the Func field is nil.
//
// Only exported methods are accessible and they are sorted in
// lexicographic order.
//Method(int) Method
// MethodByName returns the method with that name in the type's
// method set and a boolean indicating if the method was found.
//
// For a non-interface type T or *T, the returned Method's Type and Func
// fields describe a function whose first argument is the receiver.
//
// For an interface type, the returned Method's Type field gives the
// method signature, without a receiver, and the Func field is nil.
//MethodByName(string) (Method, bool)
// NumMethod returns the number of exported methods in the type's method set.
NumMethod() int
// Name returns the type's name within its package for a defined type.
// For other (non-defined) types it returns the empty string.
Name() string
// PkgPath returns a defined type's package path, that is, the import path
// that uniquely identifies the package, such as "encoding/base64".
// If the type was predeclared (string, error) or not defined (*T, struct{},
// []int, or A where A is an alias for a non-defined type), the package path
// will be the empty string.
//PkgPath() string
// Size returns the number of bytes needed to store
// a value of the given type; it is analogous to unsafe.Sizeof.
Size() uintptr
// String returns a string representation of the type.
// The string representation may use shortened package names
// (e.g., base64 instead of "encoding/base64") and is not
// guaranteed to be unique among types. To test for type identity,
// compare the Types directly.
String() string
// Kind returns the specific kind of this type.
Kind() Kind
// Implements reports whether the type implements the interface type u.
Implements(u Type) bool
// AssignableTo reports whether a value of the type is assignable to type u.
AssignableTo(u Type) bool
// ConvertibleTo reports whether a value of the type is convertible to type u.
ConvertibleTo(u Type) bool
// Comparable reports whether values of this type are comparable.
Comparable() bool
// Methods applicable only to some types, depending on Kind.
// The methods allowed for each kind are:
//
// Int*, Uint*, Float*, Complex*: Bits
// Array: Elem, Len
// Chan: ChanDir, Elem
// Func: In, NumIn, Out, NumOut, IsVariadic.
// Map: Key, Elem
// Ptr: Elem
// Slice: Elem
// Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField
// Bits returns the size of the type in bits.
// It panics if the type's Kind is not one of the
// sized or unsized Int, Uint, Float, or Complex kinds.
Bits() int
// ChanDir returns a channel type's direction.
// It panics if the type's Kind is not Chan.
//ChanDir() ChanDir
// IsVariadic reports whether a function type's final input parameter
// is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
// implicit actual type []T.
//
// For concreteness, if t represents func(x int, y ... float64), then
//
// t.NumIn() == 2
// t.In(0) is the reflect.Type for "int"
// t.In(1) is the reflect.Type for "[]float64"
// t.IsVariadic() == true
//
// IsVariadic panics if the type's Kind is not Func.
//IsVariadic() bool
// Elem returns a type's element type.
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
Elem() Type
// Field returns a struct type's i'th field.
// It panics if the type's Kind is not Struct.
// It panics if i is not in the range [0, NumField()).
Field(i int) StructField
// FieldByIndex returns the nested field corresponding
// to the index sequence. It is equivalent to calling Field
// successively for each index i.
// It panics if the type's Kind is not Struct.
//FieldByIndex(index []int) StructField
// FieldByName returns the struct field with the given name
// and a boolean indicating if the field was found.
//FieldByName(name string) (StructField, bool)
// FieldByNameFunc returns the struct field with a name
// that satisfies the match function and a boolean indicating if
// the field was found.
//
// FieldByNameFunc considers the fields in the struct itself
// and then the fields in any embedded structs, in breadth first order,
// stopping at the shallowest nesting depth containing one or more
// fields satisfying the match function. If multiple fields at that depth
// satisfy the match function, they cancel each other
// and FieldByNameFunc returns no match.
// This behavior mirrors Go's handling of name lookup in
// structs containing embedded fields.
//FieldByNameFunc(match func(string) bool) (StructField, bool)
// In returns the type of a function type's i'th input parameter.
// It panics if the type's Kind is not Func.
// It panics if i is not in the range [0, NumIn()).
//In(i int) Type
// Key returns a map type's key type.
// It panics if the type's Kind is not Map.
Key() Type
// Len returns an array type's length.
// It panics if the type's Kind is not Array.
Len() int
// NumField returns a struct type's field count.
// It panics if the type's Kind is not Struct.
NumField() int
// NumIn returns a function type's input parameter count.
// It panics if the type's Kind is not Func.
//NumIn() int
// NumOut returns a function type's output parameter count.
// It panics if the type's Kind is not Func.
//NumOut() int
// Out returns the type of a function type's i'th output parameter.
// It panics if the type's Kind is not Func.
// It panics if i is not in the range [0, NumOut()).
//Out(i int) Type
}
// The typecode as used in an interface{}.
type Type uintptr
type rawType uintptr
func TypeOf(i interface{}) Type {
return ValueOf(i).typecode
}
func PtrTo(t Type) Type {
ptrType := t<<5 | 5 // 0b0101 == 5
ptrType := t.(rawType)<<5 | 5 // 0b0101 == 5
if ptrType>>5 != t {
panic("reflect: PtrTo type does not fit")
}
return ptrType
}
func (t Type) String() string {
func (t rawType) String() string {
return "T"
}
func (t Type) Kind() Kind {
func (t rawType) Kind() Kind {
if t%2 == 0 {
// basic type
return Kind((t >> 1) % 32)
@@ -156,14 +344,18 @@ func (t Type) Kind() Kind {
// Elem returns the element type for channel, slice and array types, the
// pointed-to value for pointer types, and the key type for map types.
func (t Type) Elem() Type {
func (t rawType) Elem() Type {
return t.elem()
}
func (t rawType) elem() rawType {
switch t.Kind() {
case Chan, Ptr, Slice:
return t.stripPrefix()
case Array:
index := t.stripPrefix()
elem, _ := readVarint(unsafe.Pointer(uintptr(unsafe.Pointer(&arrayTypesSidetable)) + uintptr(index)))
return Type(elem)
return rawType(elem)
default: // not implemented: Map
panic("unimplemented: (reflect.Type).Elem()")
}
@@ -175,14 +367,14 @@ func (t Type) Elem() Type {
// simply shifted off.
//
// The behavior is only defined for non-basic types.
func (t Type) stripPrefix() Type {
func (t rawType) stripPrefix() rawType {
// Look at the 'n' bit in the type code (see the top of this file) to see
// whether this is a named type.
if (t>>4)%2 != 0 {
// This is a named type. The data is stored in a sidetable.
namedTypeNum := t >> 5
n := *(*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&namedNonBasicTypesSidetable)) + uintptr(namedTypeNum)*unsafe.Sizeof(uintptr(0))))
return Type(n)
return rawType(n)
}
// Not a named type, so the value is stored directly in the type code.
return t >> 5
@@ -190,7 +382,23 @@ func (t Type) stripPrefix() Type {
// Field returns the type of the i'th field of this struct type. It panics if t
// is not a struct type.
func (t Type) Field(i int) StructField {
func (t rawType) Field(i int) StructField {
field := t.rawField(i)
return StructField{
Name: field.Name,
PkgPath: field.PkgPath,
Type: field.Type, // note: converts rawType to Type
Tag: field.Tag,
Anonymous: field.Anonymous,
Offset: field.Offset,
}
}
// rawField returns nearly the same value as Field but without converting the
// Type member to an interface.
//
// For internal use only.
func (t rawType) rawField(i int) rawStructField {
if t.Kind() != Struct {
panic(&TypeError{"Field"})
}
@@ -206,7 +414,7 @@ func (t Type) Field(i int) StructField {
// efficient, but it is easy to implement.
// Adding a jump table at the start to jump to the field directly would
// make this much faster, but that would also impact code size.
field := StructField{}
field := rawStructField{}
offset := uintptr(0)
for fieldNum := 0; fieldNum <= i; fieldNum++ {
// Read some flags of this field, like whether the field is an
@@ -215,15 +423,16 @@ func (t Type) Field(i int) StructField {
p = unsafe.Pointer(uintptr(p) + 1)
// Read the type of this struct field.
var fieldType uintptr
fieldType, p = readVarint(p)
field.Type = Type(fieldType)
var fieldTypeVal uintptr
fieldTypeVal, p = readVarint(p)
fieldType := rawType(fieldTypeVal)
field.Type = fieldType
// Move Offset forward to align it to this field's alignment.
// Assume alignment is a power of two.
offset = align(offset, uintptr(field.Type.Align()))
offset = align(offset, uintptr(fieldType.Align()))
field.Offset = offset
offset += field.Type.Size() // starting (unaligned) offset for next field
offset += fieldType.Size() // starting (unaligned) offset for next field
// Read the field name.
var nameNum uintptr
@@ -264,7 +473,7 @@ func (t Type) Field(i int) StructField {
// Bits returns the number of bits that this type uses. It is only valid for
// arithmetic types (integers, floats, and complex numbers). For other types, it
// will panic.
func (t Type) Bits() int {
func (t rawType) Bits() int {
kind := t.Kind()
if kind >= Int && kind <= Complex128 {
return int(t.Size()) * 8
@@ -274,7 +483,7 @@ func (t Type) Bits() int {
// Len returns the number of elements in this array. It panics of the type kind
// is not Array.
func (t Type) Len() int {
func (t rawType) Len() int {
if t.Kind() != Array {
panic(TypeError{"Len"})
}
@@ -290,7 +499,7 @@ func (t Type) Len() int {
// NumField returns the number of fields of a struct type. It panics for other
// type kinds.
func (t Type) NumField() int {
func (t rawType) NumField() int {
if t.Kind() != Struct {
panic(&TypeError{"NumField"})
}
@@ -301,7 +510,7 @@ func (t Type) NumField() int {
// Size returns the size in bytes of a given type. It is similar to
// unsafe.Sizeof.
func (t Type) Size() uintptr {
func (t rawType) Size() uintptr {
switch t.Kind() {
case Bool, Int8, Uint8:
return 1
@@ -324,21 +533,24 @@ func (t Type) Size() uintptr {
case Complex128:
return 16
case String:
return unsafe.Sizeof(StringHeader{})
return unsafe.Sizeof("")
case UnsafePointer, Chan, Map, Ptr:
return unsafe.Sizeof(uintptr(0))
case Slice:
return unsafe.Sizeof(SliceHeader{})
return unsafe.Sizeof([]int{})
case Interface:
return unsafe.Sizeof(interface{}(nil))
case Func:
var f func()
return unsafe.Sizeof(f)
case Array:
return t.Elem().Size() * uintptr(t.Len())
return t.elem().Size() * uintptr(t.Len())
case Struct:
numField := t.NumField()
if numField == 0 {
return 0
}
lastField := t.Field(numField - 1)
lastField := t.rawField(numField - 1)
return lastField.Offset + lastField.Type.Size()
default:
panic("unimplemented: size of type")
@@ -347,7 +559,7 @@ func (t Type) Size() uintptr {
// Align returns the alignment of this type. It is similar to calling
// unsafe.Alignof.
func (t Type) Align() int {
func (t rawType) Align() int {
switch t.Kind() {
case Bool, Int8, Uint8:
return int(unsafe.Alignof(int8(0)))
@@ -370,25 +582,28 @@ func (t Type) Align() int {
case Complex128:
return int(unsafe.Alignof(complex128(0)))
case String:
return int(unsafe.Alignof(StringHeader{}))
return int(unsafe.Alignof(""))
case UnsafePointer, Chan, Map, Ptr:
return int(unsafe.Alignof(uintptr(0)))
case Slice:
return int(unsafe.Alignof(SliceHeader{}))
return int(unsafe.Alignof([]int(nil)))
case Interface:
return int(unsafe.Alignof(interface{}(nil)))
case Func:
var f func()
return int(unsafe.Alignof(f))
case Struct:
numField := t.NumField()
alignment := 1
for i := 0; i < numField; i++ {
fieldAlignment := t.Field(i).Type.Align()
fieldAlignment := t.rawField(i).Type.Align()
if fieldAlignment > alignment {
alignment = fieldAlignment
}
}
return alignment
case Array:
return t.Elem().Align()
return t.elem().Align()
default:
panic("unimplemented: alignment of type")
}
@@ -396,31 +611,31 @@ func (t Type) Align() int {
// FieldAlign returns the alignment if this type is used in a struct field. It
// is currently an alias for Align() but this might change in the future.
func (t Type) FieldAlign() int {
func (t rawType) FieldAlign() int {
return t.Align()
}
// AssignableTo returns whether a value of type u can be assigned to a variable
// of type t.
func (t Type) AssignableTo(u Type) bool {
if t == u {
// AssignableTo returns whether a value of type t can be assigned to a variable
// of type u.
func (t rawType) AssignableTo(u Type) bool {
if t == u.(rawType) {
return true
}
if t.Kind() == Interface {
panic("reflect: unimplemented: assigning to interface of different type")
if u.Kind() == Interface {
panic("reflect: unimplemented: AssignableTo with interface")
}
return false
}
func (t Type) Implements(u Type) bool {
if t.Kind() != Interface {
func (t rawType) Implements(u Type) bool {
if u.Kind() != Interface {
panic("reflect: non-interface type passed to Type.Implements")
}
return u.AssignableTo(t)
return t.AssignableTo(u)
}
// Comparable returns whether values of this type can be compared to each other.
func (t Type) Comparable() bool {
func (t rawType) Comparable() bool {
switch t.Kind() {
case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
return true
@@ -439,7 +654,7 @@ func (t Type) Comparable() bool {
case Slice:
return false
case Array:
return t.Elem().Comparable()
return t.elem().Comparable()
case Func:
return false
case Map:
@@ -447,7 +662,7 @@ func (t Type) Comparable() bool {
case Struct:
numField := t.NumField()
for i := 0; i < numField; i++ {
if !t.Field(i).Type.Comparable() {
if !t.rawField(i).Type.Comparable() {
return false
}
}
@@ -457,19 +672,19 @@ func (t Type) Comparable() bool {
}
}
func (t Type) ConvertibleTo(u Type) bool {
func (t rawType) ConvertibleTo(u Type) bool {
panic("unimplemented: (reflect.Type).ConvertibleTo()")
}
func (t Type) NumMethod() int {
func (t rawType) NumMethod() int {
panic("unimplemented: (reflect.Type).NumMethod()")
}
func (t Type) Name() string {
func (t rawType) Name() string {
panic("unimplemented: (reflect.Type).Name()")
}
func (t Type) Key() Type {
func (t rawType) Key() Type {
panic("unimplemented: (reflect.Type).Key()")
}
@@ -488,6 +703,18 @@ type StructField struct {
Offset uintptr
}
// rawStructField is the same as StructField but with the Type member replaced
// with rawType. For internal use only. Avoiding this conversion to the Type
// interface improves code size in many cases.
type rawStructField struct {
Name string
PkgPath string
Type rawType
Tag StructTag
Anonymous bool
Offset uintptr
}
// A StructTag is the tag string in a struct field.
type StructTag string
+75 -32
View File
@@ -16,7 +16,7 @@ const (
)
type Value struct {
typecode Type
typecode rawType
value unsafe.Pointer
flags valueFlags
}
@@ -28,6 +28,13 @@ func (v Value) isIndirect() bool {
return v.flags&valueFlagIndirect != 0
}
// isExported returns whether the value represented by this Value could be
// accessed without violating type system constraints. For example, it is not
// set for unexported struct fields.
func (v Value) isExported() bool {
return v.flags&valueFlagExported != 0
}
func Indirect(v Value) Value {
if v.Kind() != Ptr {
return v
@@ -36,10 +43,10 @@ func Indirect(v Value) Value {
}
//go:linkname composeInterface runtime.composeInterface
func composeInterface(Type, unsafe.Pointer) interface{}
func composeInterface(rawType, unsafe.Pointer) interface{}
//go:linkname decomposeInterface runtime.decomposeInterface
func decomposeInterface(i interface{}) (Type, unsafe.Pointer)
func decomposeInterface(i interface{}) (rawType, unsafe.Pointer)
func ValueOf(i interface{}) Value {
typecode, value := decomposeInterface(i)
@@ -51,11 +58,20 @@ func ValueOf(i interface{}) Value {
}
func (v Value) Interface() interface{} {
if v.isIndirect() && v.Type().Size() <= unsafe.Sizeof(uintptr(0)) {
if !v.isExported() {
panic("(reflect.Value).Interface: unexported")
}
return valueInterfaceUnsafe(v)
}
// valueInterfaceUnsafe is used by the runtime to hash map keys. It should not
// be subject to the isExported check.
func valueInterfaceUnsafe(v Value) interface{} {
if v.isIndirect() && v.typecode.Size() <= unsafe.Sizeof(uintptr(0)) {
// Value was indirect but must be put back directly in the interface
// value.
var value uintptr
for j := v.Type().Size(); j != 0; j-- {
for j := v.typecode.Size(); j != 0; j-- {
value = (value << 8) | uintptr(*(*uint8)(unsafe.Pointer(uintptr(v.value) + j - 1)))
}
v.value = unsafe.Pointer(value)
@@ -67,8 +83,16 @@ func (v Value) Type() Type {
return v.typecode
}
// Internal function only, do not use.
//
// RawType returns the raw, underlying type code. It is used in the runtime
// package and needs to be exported for the runtime package to access it.
func (v Value) RawType() rawType {
return v.typecode
}
func (v Value) Kind() Kind {
return v.Type().Kind()
return v.typecode.Kind()
}
// IsNil returns whether the value is the nil value. It panics if the value Kind
@@ -132,7 +156,7 @@ func (v Value) CanInterface() bool {
}
func (v Value) CanAddr() bool {
panic("unimplemented: (reflect.Value).CanAddr()")
return v.flags&(valueFlagIndirect) == valueFlagIndirect
}
func (v Value) Addr() Value {
@@ -313,10 +337,9 @@ func chanlen(p unsafe.Pointer) int
// Len returns the length of this value for slices, strings, arrays, channels,
// and maps. For other types, it panics.
func (v Value) Len() int {
t := v.Type()
switch t.Kind() {
switch v.typecode.Kind() {
case Array:
return v.Type().Len()
return v.typecode.Len()
case Chan:
return chanlen(v.value)
case Map:
@@ -336,10 +359,9 @@ func chancap(p unsafe.Pointer) int
// Cap returns the capacity of this value for arrays, channels and slices.
// For other types, it panics.
func (v Value) Cap() int {
t := v.Type()
switch t.Kind() {
switch v.typecode.Kind() {
case Array:
return v.Type().Len()
return v.typecode.Len()
case Chan:
return chancap(v.value)
case Slice:
@@ -352,7 +374,7 @@ func (v Value) Cap() int {
// NumField returns the number of fields of this struct. It panics for other
// value types.
func (v Value) NumField() int {
return v.Type().NumField()
return v.typecode.NumField()
}
func (v Value) Elem() Value {
@@ -366,7 +388,7 @@ func (v Value) Elem() Value {
return Value{}
}
return Value{
typecode: v.Type().Elem(),
typecode: v.typecode.elem(),
value: ptr,
flags: v.flags | valueFlagIndirect,
}
@@ -377,7 +399,7 @@ func (v Value) Elem() Value {
// Field returns the value of the i'th field of this struct.
func (v Value) Field(i int) Value {
structField := v.Type().Field(i)
structField := v.typecode.rawField(i)
flags := v.flags
if structField.PkgPath != "" {
// The fact that PkgPath is present means that this field is not
@@ -385,14 +407,15 @@ func (v Value) Field(i int) Value {
flags &^= valueFlagExported
}
size := v.Type().Size()
fieldSize := structField.Type.Size()
size := v.typecode.Size()
fieldType := structField.Type
fieldSize := fieldType.Size()
if v.isIndirect() || fieldSize > unsafe.Sizeof(uintptr(0)) {
// v.value was already a pointer to the value and it should stay that
// way.
return Value{
flags: flags,
typecode: structField.Type,
typecode: fieldType,
value: unsafe.Pointer(uintptr(v.value) + structField.Offset),
}
}
@@ -407,7 +430,7 @@ func (v Value) Field(i int) Value {
// situation explicitly.
return Value{
flags: flags,
typecode: structField.Type,
typecode: fieldType,
value: unsafe.Pointer(uintptr(0)),
}
}
@@ -420,7 +443,7 @@ func (v Value) Field(i int) Value {
value := unsafe.Pointer(loadValue(ptr, fieldSize))
return Value{
flags: 0,
typecode: structField.Type,
typecode: fieldType,
value: value,
}
}
@@ -430,7 +453,7 @@ func (v Value) Field(i int) Value {
value := maskAndShift(uintptr(v.value), structField.Offset, fieldSize)
return Value{
flags: flags,
typecode: structField.Type,
typecode: fieldType,
value: unsafe.Pointer(value),
}
}
@@ -444,10 +467,10 @@ func (v Value) Index(i int) Value {
panic("reflect: slice index out of range")
}
elem := Value{
typecode: v.Type().Elem(),
typecode: v.typecode.elem(),
flags: v.flags | valueFlagIndirect,
}
addr := uintptr(slice.Data) + elem.Type().Size()*uintptr(i) // pointer to new value
addr := uintptr(slice.Data) + elem.typecode.Size()*uintptr(i) // pointer to new value
elem.value = unsafe.Pointer(addr)
return elem
case String:
@@ -464,13 +487,13 @@ func (v Value) Index(i int) Value {
}
case Array:
// Extract an element from the array.
elemType := v.Type().Elem()
elemType := v.typecode.elem()
elemSize := elemType.Size()
size := v.Type().Size()
size := v.typecode.Size()
if size == 0 {
// The element size is 0 and/or the length of the array is 0.
return Value{
typecode: v.Type().Elem(),
typecode: v.typecode.elem(),
flags: v.flags,
}
}
@@ -481,7 +504,7 @@ func (v Value) Index(i int) Value {
// elemSize.
addr := uintptr(v.value) + elemSize*uintptr(i) // pointer to new value
return Value{
typecode: v.Type().Elem(),
typecode: v.typecode.elem(),
flags: v.flags,
value: unsafe.Pointer(addr),
}
@@ -492,7 +515,7 @@ func (v Value) Index(i int) Value {
// Load the value from the pointer.
addr := uintptr(v.value) + elemSize*uintptr(i) // pointer to new value
return Value{
typecode: v.Type().Elem(),
typecode: v.typecode.elem(),
flags: v.flags,
value: unsafe.Pointer(loadValue(unsafe.Pointer(addr), elemSize)),
}
@@ -503,7 +526,7 @@ func (v Value) Index(i int) Value {
offset := elemSize * uintptr(i)
value := maskAndShift(uintptr(v.value), offset, elemSize)
return Value{
typecode: v.Type().Elem(),
typecode: v.typecode.elem(),
flags: v.flags,
value: unsafe.Pointer(value),
}
@@ -532,6 +555,14 @@ func maskAndShift(value, offset, size uintptr) uintptr {
return (uintptr(value) >> (offset * 8)) & mask
}
func (v Value) NumMethod() int {
return v.typecode.NumMethod()
}
func (v Value) OverflowFloat(x float64) bool {
panic("unimplemented: (reflect.Value).OverflowFloat()")
}
func (v Value) MapKeys() []Value {
panic("unimplemented: (reflect.Value).MapKeys()")
}
@@ -561,10 +592,10 @@ func (it *MapIter) Next() bool {
func (v Value) Set(x Value) {
v.checkAddressable()
if !v.Type().AssignableTo(x.Type()) {
if !v.typecode.AssignableTo(x.typecode) {
panic("reflect: cannot set")
}
size := v.Type().Size()
size := v.typecode.Size()
xptr := x.value
if size <= unsafe.Sizeof(uintptr(0)) && !x.isIndirect() {
value := x.value
@@ -655,6 +686,18 @@ func (v Value) SetString(x string) {
}
}
func (v Value) SetBytes(x []byte) {
panic("unimplemented: (reflect.Value).SetBytes()")
}
func (v Value) SetCap(n int) {
panic("unimplemented: (reflect.Value).SetCap()")
}
func (v Value) SetLen(n int) {
panic("unimplemented: (reflect.Value).SetLen()")
}
func (v Value) checkAddressable() {
if !v.isIndirect() {
panic("reflect: value is not addressable")
+16 -9
View File
@@ -349,48 +349,55 @@ func hashmapStringDelete(m *hashmap, key string) {
// Hashmap with interface keys (for everything else).
// This is a method that is intentionally unexported in the reflect package. It
// is identical to the Interface() method call, except it doesn't check whether
// a field is exported and thus allows circumventing the type system.
// The hash function needs it as it also needs to hash unexported struct fields.
//go:linkname valueInterfaceUnsafe reflect.valueInterfaceUnsafe
func valueInterfaceUnsafe(v reflect.Value) interface{}
func hashmapInterfaceHash(itf interface{}) uint32 {
x := reflect.ValueOf(itf)
if x.Type() == 0 {
if x.RawType() == 0 {
return 0 // nil interface
}
value := (*_interface)(unsafe.Pointer(&itf)).value
ptr := value
if x.Type().Size() <= unsafe.Sizeof(uintptr(0)) {
if x.RawType().Size() <= unsafe.Sizeof(uintptr(0)) {
// Value fits in pointer, so it's directly stored in the pointer.
ptr = unsafe.Pointer(&value)
}
switch x.Type().Kind() {
switch x.RawType().Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return hashmapHash(ptr, x.Type().Size())
return hashmapHash(ptr, x.RawType().Size())
case reflect.Bool, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return hashmapHash(ptr, x.Type().Size())
return hashmapHash(ptr, x.RawType().Size())
case reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
// 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
// time may become exponential. To fix that, it would be better to
// return a random number instead:
// https://research.swtch.com/randhash
return hashmapHash(ptr, x.Type().Size())
return hashmapHash(ptr, x.RawType().Size())
case reflect.String:
return hashmapStringHash(x.String())
case reflect.Chan, reflect.Ptr, reflect.UnsafePointer:
// 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.Type().Size())
return hashmapHash(ptr, x.RawType().Size())
case reflect.Array:
var hash uint32
for i := 0; i < x.Len(); i++ {
hash |= hashmapInterfaceHash(x.Index(i).Interface())
hash |= hashmapInterfaceHash(valueInterfaceUnsafe(x.Index(i)))
}
return hash
case reflect.Struct:
var hash uint32
for i := 0; i < x.NumField(); i++ {
hash |= hashmapInterfaceHash(x.Field(i).Interface())
hash |= hashmapInterfaceHash(valueInterfaceUnsafe(x.Field(i)))
}
return hash
default:
+10 -14
View File
@@ -31,18 +31,21 @@ func interfaceEqual(x, y interface{}) bool {
}
func reflectValueEqual(x, y reflect.Value) bool {
if x.Type() == 0 || y.Type() == 0 {
// Note: doing a x.Type() == y.Type() comparison would not work here as that
// would introduce an infinite recursion: comparing two reflect.Type values
// is done with this reflectValueEqual runtime call.
if x.RawType() == 0 || y.RawType() == 0 {
// One of them is nil.
return x.Type() == y.Type()
return x.RawType() == y.RawType()
}
if x.Type() != y.Type() {
if x.RawType() != y.RawType() {
// The type is not the same, which means the interfaces are definitely
// not the same.
return false
}
switch x.Type().Kind() {
switch x.RawType().Kind() {
case reflect.Bool:
return x.Bool() == y.Bool()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@@ -107,6 +110,8 @@ type typecodeID struct {
// The array length, for array types.
length uintptr
methodSet *interfaceMethodInfo // nil or a GEP of an array
}
// structField is used by the compiler to pass information to the interface
@@ -118,20 +123,11 @@ type structField struct {
embedded bool
}
// Pseudo type used before interface lowering. By using a struct instead of a
// function call, this is simpler to reason about during init interpretation
// than a function call. Also, by keeping the method set around it is easier to
// implement interfaceImplements in the interp package.
type typeInInterface struct {
typecode *typecodeID // element type, underlying type, or reference to struct fields
methodSet *interfaceMethodInfo // nil or a GEP of an array
}
// Pseudo function call used during a type assert. It is used during interface
// lowering, to assign the lowest type numbers to the types with the most type
// asserts. Also, it is replaced with const false if this type assert can never
// happen.
func typeAssert(actualType uintptr, assertedType *typecodeID) bool
func typeAssert(actualType uintptr, assertedType *uint8) bool
// Pseudo function call that returns whether a given type implements all methods
// of the given interface.
+1
View File
@@ -56,6 +56,7 @@ func nanosecondsToTicks(ns int64) timeUnit {
}
// number of ticks (microseconds) since start.
//go:linkname ticks runtime.ticks
func ticks() timeUnit {
return timeUnit(tickCount.Get())
}
+262
View File
@@ -0,0 +1,262 @@
// +build stm32,stm32l4x2
package runtime
import (
"device/stm32"
"machine"
)
/*
clock settings
+-------------+-----------+
| LSE | 32.768khz |
| SYSCLK | 80mhz |
| HCLK | 80mhz |
| APB1(PCLK1) | 80mhz |
| APB2(PCLK2) | 80mhz |
+-------------+-----------+
*/
const (
HSE_STARTUP_TIMEOUT = 0x0500
PLL_M = 1
PLL_N = 40
PLL_P = RCC_PLLP_DIV7
PLL_Q = RCC_PLLQ_DIV2
PLL_R = RCC_PLLR_DIV2
MSIRANGE = stm32.RCC_CR_MSIRANGE_Range4M
PWR_CR1_VOS_0 = 1 << stm32.PWR_CR1_VOS_Pos
PWR_CR1_VOS_1 = 2 << stm32.PWR_CR1_VOS_Pos
PWR_REGULATOR_VOLTAGE_SCALE1 = PWR_CR1_VOS_0
PWR_REGULATOR_VOLTAGE_SCALE2 = PWR_CR1_VOS_1
FLASH_LATENCY_0 = 0
FLASH_LATENCY_1 = 1
FLASH_LATENCY_2 = 2
FLASH_LATENCY_3 = 3
FLASH_LATENCY_4 = 4
RCC_PLLP_DIV7 = 7
RCC_PLLQ_DIV2 = 2
RCC_PLLR_DIV2 = 2
RCC_CFGR_SWS_MSI = 0x0
RCC_CFGR_SWS_PLL = 0xC
RCC_PLLSOURCE_MSI = 1
RCC_PLL_SYSCLK = stm32.RCC_PLLCFGR_PLLREN
)
/*
timer settings used for tick and sleep.
note: TICK_TIMER_FREQ and SLEEP_TIMER_FREQ are controlled by PLL / clock
settings above, so must be kept in sync if the clock settings are changed.
*/
const (
TICK_RATE = 1000 // 1 KHz
TICK_TIMER_IRQ = stm32.IRQ_TIM1_UP_TIM16
TICK_TIMER_FREQ = 80000000 // 80 MHz
SLEEP_TIMER_IRQ = stm32.IRQ_TIM1_BRK_TIM15
SLEEP_TIMER_FREQ = 80000000 // 84 MHz
)
type arrtype = uint32
const asyncScheduler = false
func init() {
initCLK()
initSleepTimer(&timerInfo{
EnableRegister: &stm32.RCC.APB2ENR,
EnableFlag: stm32.RCC_APB2ENR_TIM15EN,
Device: stm32.TIM15,
})
machine.UART0.Configure(machine.UARTConfig{})
initTickTimer(&timerInfo{
EnableRegister: &stm32.RCC.APB2ENR,
EnableFlag: stm32.RCC_APB2ENR_TIM16EN,
Device: stm32.TIM16,
})
}
func putchar(c byte) {
machine.UART0.WriteByte(c)
}
func initCLK() {
// PWR_CLK_ENABLE
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_PWREN)
_ = stm32.RCC.APB1ENR1.Get()
// Disable Backup domain protection
if !stm32.PWR.CR1.HasBits(stm32.PWR_CR1_DBP) {
stm32.PWR.CR1.SetBits(stm32.PWR_CR1_DBP)
for !stm32.PWR.CR1.HasBits(stm32.PWR_CR1_DBP) {
}
}
// Set LSE Drive to LOW
stm32.RCC.BDCR.ReplaceBits(0, stm32.RCC_BDCR_LSEDRV_Msk, 0)
// Initialize the High-Speed External Oscillator
initOsc()
// PWR_VOLTAGESCALING_CONFIG
stm32.PWR.CR1.ReplaceBits(0, stm32.PWR_CR1_VOS_Msk, 0)
_ = stm32.PWR.CR1.Get()
// Set flash wait states (min 5 latency units) based on clock
if (stm32.FLASH.ACR.Get() & 0xF) < 5 {
stm32.FLASH.ACR.ReplaceBits(5, 0xF, 0)
}
// Ensure HCLK does not exceed max during transition
stm32.RCC.CFGR.ReplaceBits(8<<stm32.RCC_CFGR_HPRE_Pos, stm32.RCC_CFGR_HPRE_Msk, 0)
// Set SYSCLK source and wait
// (3 = RCC_SYSCLKSOURCE_PLLCLK, 2=RCC_CFGR_SWS_Pos)
stm32.RCC.CFGR.ReplaceBits(3, stm32.RCC_CFGR_SW_Msk, 0)
for stm32.RCC.CFGR.Get()&(3<<2) != (3 << 2) {
}
// Set HCLK
// (0 = RCC_SYSCLKSOURCE_PLLCLK)
stm32.RCC.CFGR.ReplaceBits(0, stm32.RCC_CFGR_HPRE_Msk, 0)
// Set flash wait states (max 5 latency units) based on clock
if (stm32.FLASH.ACR.Get() & 0xF) > 5 {
stm32.FLASH.ACR.ReplaceBits(5, 0xF, 0)
}
// Set APB1 and APB2 clocks (0 = DIV1)
stm32.RCC.CFGR.ReplaceBits(0, stm32.RCC_CFGR_PPRE1_Msk, 0)
stm32.RCC.CFGR.ReplaceBits(0, stm32.RCC_CFGR_PPRE2_Msk, 0)
}
func initOsc() {
sysclkSource := stm32.RCC.CFGR.Get() & stm32.RCC_CFGR_SWS_Msk
pllConfig := stm32.RCC.PLLCFGR.Get() & stm32.RCC_PLLCFGR_PLLSRC_Msk
// Enable MSI, adjusting flash latency
if sysclkSource == RCC_CFGR_SWS_MSI ||
(sysclkSource == RCC_CFGR_SWS_PLL && pllConfig == RCC_PLLSOURCE_MSI) {
if MSIRANGE > getMSIRange() {
setFlashLatencyFromMSIRange(MSIRANGE)
setMSIFreq(MSIRANGE, 0)
} else {
setMSIFreq(MSIRANGE, 0)
if sysclkSource == RCC_CFGR_SWS_MSI {
setFlashLatencyFromMSIRange(MSIRANGE)
}
}
} else {
stm32.RCC.CR.SetBits(stm32.RCC_CR_MSION)
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_MSIRDY) {
}
setMSIFreq(MSIRANGE, 0)
}
// Enable LSE, wait until ready
stm32.RCC.BDCR.SetBits(stm32.RCC_BDCR_LSEON)
for !stm32.RCC.BDCR.HasBits(stm32.RCC_BDCR_LSEON) {
}
// Disable the PLL, wait until disabled
stm32.RCC.CR.ClearBits(stm32.RCC_CR_PLLON)
for stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
}
// Configure the PLL
stm32.RCC.PLLCFGR.ReplaceBits(
(1)| // 1 = RCC_PLLSOURCE_MSI
(PLL_M-1)<<stm32.RCC_PLLCFGR_PLLM_Pos|
(PLL_N<<stm32.RCC_PLLCFGR_PLLN_Pos)|
(((PLL_Q>>1)-1)<<stm32.RCC_PLLCFGR_PLLQ_Pos)|
(((PLL_R>>1)-1)<<stm32.RCC_PLLCFGR_PLLR_Pos)|
(PLL_P<<stm32.RCC_PLLCFGR_PLLPDIV_Pos),
stm32.RCC_PLLCFGR_PLLSRC_Msk|stm32.RCC_PLLCFGR_PLLM_Msk|
stm32.RCC_PLLCFGR_PLLN_Msk|stm32.RCC_PLLCFGR_PLLP_Msk|
stm32.RCC_PLLCFGR_PLLR_Msk|stm32.RCC_PLLCFGR_PLLPDIV_Msk,
0)
// Enable the PLL and PLL System Clock Output, wait until ready
stm32.RCC.CR.SetBits(stm32.RCC_CR_PLLON)
stm32.RCC.PLLCFGR.SetBits(stm32.RCC_PLLCFGR_PLLREN) // = RCC_PLL_SYSCLK
for !stm32.RCC.CR.HasBits(stm32.RCC_CR_PLLRDY) {
}
// Enable system clock output
stm32.RCC.PLLCFGR.SetBits(RCC_PLL_SYSCLK)
}
func getMSIRange() uint32 {
if stm32.RCC.CR.HasBits(stm32.RCC_CR_MSIRGSEL) {
return (stm32.RCC.CR.Get() & stm32.RCC_CR_MSIRANGE_Msk) >> stm32.RCC_CR_MSIRANGE_Pos
}
return (stm32.RCC.CSR.Get() & stm32.RCC_CSR_MSISRANGE_Msk) >> stm32.RCC_CSR_MSISRANGE_Pos
}
func setMSIFreq(r uint32, calibration uint32) {
stm32.RCC.CR.SetBits(stm32.RCC_CR_MSIRGSEL)
stm32.RCC.CR.ReplaceBits(r<<stm32.RCC_CR_MSIRANGE_Pos, stm32.RCC_CR_MSIRANGE_Msk, 0)
stm32.RCC.ICSCR.ReplaceBits(calibration<<stm32.RCC_ICSCR_MSITRIM_Pos, stm32.RCC_ICSCR_MSITRIM_Msk, 0)
}
func setFlashLatencyFromMSIRange(r uint32) {
var vos uint32
if pwrIsClkEnabled() {
vos = pwrExGetVoltageRange()
} else {
pwrClkEnable()
vos = pwrExGetVoltageRange()
pwrClkDisable()
}
latency := uint32(FLASH_LATENCY_0)
if vos == PWR_REGULATOR_VOLTAGE_SCALE1 {
if r > stm32.RCC_CR_MSIRANGE_Range16M {
if r > stm32.RCC_CR_MSIRANGE_Range32M {
latency = FLASH_LATENCY_2
} else {
latency = FLASH_LATENCY_1
}
}
} else if r > stm32.RCC_CR_MSIRANGE_Range16M {
latency = FLASH_LATENCY_3
} else {
if r == stm32.RCC_CR_MSIRANGE_Range16M {
latency = FLASH_LATENCY_2
} else if r == stm32.RCC_CR_MSIRANGE_Range8M {
latency = FLASH_LATENCY_1
}
}
stm32.FLASH.ACR.ReplaceBits(latency, stm32.Flash_ACR_LATENCY_Msk, 0)
}
func pwrIsClkEnabled() bool {
return stm32.RCC.APB1ENR1.HasBits(stm32.RCC_APB1ENR1_PWREN)
}
func pwrClkEnable() {
stm32.RCC.APB1ENR1.SetBits(stm32.RCC_APB1ENR1_PWREN)
}
func pwrClkDisable() {
stm32.RCC.APB1ENR1.ClearBits(stm32.RCC_APB1ENR1_PWREN)
}
func pwrExGetVoltageRange() uint32 {
return stm32.PWR.CR1.Get() & stm32.PWR_CR1_VOS_Msk
}
+5
View File
@@ -8,11 +8,16 @@ import (
type timeUnit int64
// libc constructors
//export __wasm_call_ctors
func __wasm_call_ctors()
//export _start
func _start() {
// These need to be initialized early so that the heap can be initialized.
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
__wasm_call_ctors()
run()
}
+5
View File
@@ -0,0 +1,5 @@
// +build !wasi,!darwin
package syscall
func (e Errno) Is(target error) bool { return false }
+31 -6
View File
@@ -13,12 +13,15 @@ type sliceHeader struct {
}
func Close(fd int) (err error) {
return ENOSYS // TODO
if libc_close(fd) < 0 {
err = getErrno()
}
return
}
func Write(fd int, p []byte) (n int, err error) {
buf, count := splitSlice(p)
n = libc_write(int32(fd), buf, uint(count))
n = libc_write(fd, buf, uint(count))
if n < 0 {
err = getErrno()
}
@@ -26,15 +29,25 @@ func Write(fd int, p []byte) (n int, err error) {
}
func Read(fd int, p []byte) (n int, err error) {
return 0, ENOSYS // TODO
buf, count := splitSlice(p)
n = libc_read(fd, buf, uint(count))
if n < 0 {
err = getErrno()
}
return
}
func Seek(fd int, offset int64, whence int) (off int64, err error) {
return 0, ENOSYS // TODO
}
func Open(path string, mode int, perm uint32) (fd int, err error) {
return 0, ENOSYS // TODO
func Open(path string, flag int, mode uint32) (fd int, err error) {
data := append([]byte(path), 0)
fd = libc_open(&data[0], flag, mode)
if fd < 0 {
err = getErrno()
}
return
}
func Mkdir(path string, mode uint32) (err error) {
@@ -78,8 +91,20 @@ func splitSlice(p []byte) (buf *byte, len uintptr) {
// ssize_t write(int fd, const void *buf, size_t count)
//export write
func libc_write(fd int32, buf *byte, count uint) int
func libc_write(fd int, buf *byte, count uint) int
// char *getenv(const char *name);
//export getenv
func libc_getenv(name *byte) *byte
// ssize_t read(int fd, void *buf, size_t count);
//export read
func libc_read(fd int, buf *byte, count uint) int
// int open(const char *pathname, int flags, mode_t mode);
//export open
func libc_open(pathname *byte, flags int, mode uint32) int
// int close(int fd)
//export close
func libc_close(fd int) int
+17
View File
@@ -1,3 +1,5 @@
// +build darwin
package syscall
// This file defines errno and constants to match the darwin libsystem ABI.
@@ -22,10 +24,25 @@ func getErrno() Errno {
return Errno(uintptr(*errptr))
}
func (e Errno) Is(target error) bool {
switch target.Error() {
case "permission denied":
return e == EACCES || e == EPERM
case "file already exists":
return e == EEXIST
case "file does not exist":
return e == ENOENT
}
return false
}
const (
EPERM Errno = 0x1
ENOENT Errno = 0x2
EACCES Errno = 0xd
EEXIST Errno = 0x11
EINTR Errno = 0x4
ENOTDIR Errno = 0x14
EMFILE Errno = 0x18
EAGAIN Errno = 0x23
ETIMEDOUT Errno = 0x3c
+3 -5
View File
@@ -2,8 +2,6 @@
package syscall
import "errors"
// A Signal is a number describing a process signal.
// It implements the os.Signal interface.
type Signal int
@@ -32,7 +30,6 @@ const (
O_RDWR = 2
O_CREAT = 0100
O_CREATE = O_CREAT
O_TRUNC = 01000
O_APPEND = 02000
O_EXCL = 0200
@@ -41,8 +38,9 @@ const (
O_CLOEXEC = 0
)
var dummyError = errors.New("unknown syscall error")
//go:extern errno
var libcErrno uintptr
func getErrno() error {
return dummyError
return Errno(libcErrno)
}
+92 -1
View File
@@ -33,7 +33,6 @@ const (
O_RDWR = O_RDONLY | O_WRONLY
O_CREAT = __WASI_OFLAGS_CREAT << 12
O_CREATE = O_CREAT
O_TRUNC = __WASI_OFLAGS_TRUNC << 12
O_APPEND = __WASI_FDFLAGS_APPEND
O_EXCL = __WASI_OFLAGS_EXCL << 12
@@ -48,3 +47,95 @@ var libcErrno uintptr
func getErrno() error {
return Errno(libcErrno)
}
func (e Errno) Is(target error) bool {
switch target.Error() {
case "permission denied":
return e == EACCES || e == EPERM || e == ENOTCAPABLE // ENOTCAPABLE is unique in WASI
case "file already exists":
return e == EEXIST || e == ENOTEMPTY
case "file does not exist":
return e == ENOENT
}
return false
}
// https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/__errno.h
const (
E2BIG Errno = 1 /* Argument list too long */
EACCES Errno = 2 /* Permission denied */
EADDRINUSE Errno = 3 /* Address already in use */
EADDRNOTAVAIL Errno = 4 /* Address not available */
EAFNOSUPPORT Errno = 5 /* Address family not supported by protocol family */
EAGAIN Errno = 6 /* Try again */
EWOULDBLOCK Errno = EAGAIN /* Operation would block */
EALREADY Errno = 7 /* Socket already connected */
EBADF Errno = 8 /* Bad file number */
EBADMSG Errno = 9 /* Trying to read unreadable message */
EBUSY Errno = 10 /* Device or resource busy */
ECANCELED Errno = 11 /* Operation canceled. */
ECHILD Errno = 12 /* No child processes */
ECONNABORTED Errno = 13 /* Connection aborted */
ECONNREFUSED Errno = 14 /* Connection refused */
ECONNRESET Errno = 15 /* Connection reset by peer */
EDEADLK Errno = 16 /* Deadlock condition */
EDESTADDRREQ Errno = 17 /* Destination address required */
EDOM Errno = 18 /* Math arg out of domain of func */
EDQUOT Errno = 19 /* Quota exceeded */
EEXIST Errno = 20 /* File exists */
EFAULT Errno = 21 /* Bad address */
EFBIG Errno = 22 /* File too large */
EHOSTUNREACH Errno = 23 /* Host is unreachable */
EIDRM Errno = 24 /* Identifier removed */
EILSEQ Errno = 25
EINPROGRESS Errno = 26 /* Connection already in progress */
EINTR Errno = 27 /* Interrupted system call */
EINVAL Errno = 28 /* Invalid argument */
EIO Errno = 29 /* I/O error */
EISCONN Errno = 30 /* Socket is already connected */
EISDIR Errno = 31 /* Is a directory */
ELOOP Errno = 32 /* Too many symbolic links */
EMFILE Errno = 33 /* Too many open files */
EMLINK Errno = 34 /* Too many links */
EMSGSIZE Errno = 35 /* Message too long */
EMULTIHOP Errno = 36 /* Multihop attempted */
ENAMETOOLONG Errno = 37 /* File name too long */
ENETDOWN Errno = 38 /* Network interface is not configured */
ENETRESET Errno = 39
ENETUNREACH Errno = 40 /* Network is unreachable */
ENFILE Errno = 41 /* File table overflow */
ENOBUFS Errno = 42 /* No buffer space available */
ENODEV Errno = 43 /* No such device */
ENOENT Errno = 44 /* No such file or directory */
ENOEXEC Errno = 45 /* Exec format error */
ENOLCK Errno = 46 /* No record locks available */
ENOLINK Errno = 47 /* The link has been severed */
ENOMEM Errno = 48 /* Out of memory */
ENOMSG Errno = 49 /* No message of desired type */
ENOPROTOOPT Errno = 50 /* Protocol not available */
ENOSPC Errno = 51 /* No space left on device */
ENOSYS Errno = 52 /* Function not implemented */
ENOTCONN Errno = 53 /* Socket is not connected */
ENOTDIR Errno = 54 /* Not a directory */
ENOTEMPTY Errno = 55 /* Directory not empty */
ENOTSOCK Errno = 57 /* Socket operation on non-socket */
ESOCKTNOSUPPORT Errno = 58 /* Socket type not supported */
EOPNOTSUPP Errno = 58 /* Operation not supported on transport endpoint */
ENOTSUP Errno = EOPNOTSUPP /* Not supported */
ENOTTY Errno = 59 /* Not a typewriter */
ENXIO Errno = 60 /* No such device or address */
EOVERFLOW Errno = 61 /* Value too large for defined data type */
EPERM Errno = 63 /* Operation not permitted */
EPIPE Errno = 64 /* Broken pipe */
EPROTO Errno = 65 /* Protocol error */
EPROTONOSUPPORT Errno = 66 /* Unknown protocol */
EPROTOTYPE Errno = 67 /* Protocol wrong type for socket */
ERANGE Errno = 68 /* Math result not representable */
EROFS Errno = 69 /* Read-only file system */
ESPIPE Errno = 70 /* Illegal seek */
ESRCH Errno = 71 /* No such process */
ESTALE Errno = 72
ETIMEDOUT Errno = 73 /* Connection timed out */
EXDEV Errno = 75 /* Cross-device link */
ENOTCAPABLE Errno = 76 /* Extension: Capabilities insufficient. */
)
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build baremetal nintendoswitch wasi
// +build baremetal nintendoswitch
package syscall
+1 -1
View File
@@ -19,5 +19,5 @@
"src/internal/task/task_stack_avr.S",
"src/runtime/gc_avr.S"
],
"gdb": "avr-gdb"
"gdb": ["avr-gdb"]
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"inherits": ["cortex-m"],
"llvm-target": "armv7m-none-eabi",
"build-tags": ["bluepill", "stm32f103", "stm32"],
"build-tags": ["bluepill", "stm32f103", "stm32f1", "stm32"],
"cflags": [
"--target=armv7m-none-eabi",
"-Qunused-arguments"
+1 -1
View File
@@ -28,5 +28,5 @@
"src/internal/task/task_stack_cortexm.S",
"src/runtime/gc_arm.S"
],
"gdb": "gdb-multiarch"
"gdb": ["gdb-multiarch", "arm-none-eabi-gdb"]
}
+2 -1
View File
@@ -3,6 +3,7 @@
"llvm-target": "armv7em-none-eabi",
"cflags": [
"--target=armv7em-none-eabi",
"-mfloat-abi=soft"
"-mfloat-abi=soft",
"-Qunused-arguments"
]
}
+1 -2
View File
@@ -4,6 +4,5 @@
"cflags": [
"--target=armv7em-none-eabi",
"-Qunused-arguments"
],
"gdb": "arm-none-eabi-gdb"
]
}
+1 -1
View File
@@ -27,6 +27,6 @@
"targets/gameboy-advance.s",
"src/runtime/gc_arm.S"
],
"gdb": "gdb-multiarch",
"gdb": ["gdb-multiarch"],
"emulator": ["mgba", "-3"]
}

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