mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-04 19:17:47 +00:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ecaec565aa |
@@ -107,10 +107,7 @@ 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-kendryte gen-device-nxp
|
||||
ifneq ($(STM32), 0)
|
||||
gen-device: gen-device-stm32
|
||||
endif
|
||||
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-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
|
||||
@@ -260,6 +257,8 @@ 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
|
||||
@@ -268,10 +267,6 @@ 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
|
||||
@@ -280,6 +275,14 @@ 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
|
||||
@@ -304,8 +307,12 @@ 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
|
||||
@@ -332,6 +339,10 @@ 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
|
||||
@@ -343,28 +354,6 @@ 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
|
||||
@@ -405,7 +394,6 @@ endif
|
||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
|
||||
@$(MD5SUM) test.hex
|
||||
|
||||
|
||||
wasmtest:
|
||||
$(GO) test ./tests/wasm
|
||||
|
||||
|
||||
+3
-18
@@ -7,7 +7,6 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"runtime"
|
||||
@@ -43,7 +42,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"`
|
||||
@@ -241,7 +240,7 @@ func defaultTarget(goos, goarch, triple string) (*TargetSpec, error) {
|
||||
Compiler: "clang",
|
||||
Linker: "cc",
|
||||
CFlags: []string{"--target=" + triple},
|
||||
GDB: []string{"gdb"},
|
||||
GDB: "gdb",
|
||||
PortReset: "false",
|
||||
}
|
||||
if goos == "darwin" {
|
||||
@@ -254,7 +253,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 = []string{"gdb-multiarch"}
|
||||
spec.GDB = "gdb-multiarch"
|
||||
if goarch == "arm" && goos == "linux" {
|
||||
spec.CFlags = append(spec.CFlags, "--sysroot=/usr/arm-linux-gnueabihf")
|
||||
spec.Linker = "arm-linux-gnueabihf-gcc"
|
||||
@@ -272,17 +271,3 @@ 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, ", ") + ")")
|
||||
}
|
||||
|
||||
@@ -159,9 +159,6 @@ 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
|
||||
|
||||
@@ -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 = 5 // last change: add method set to interface types
|
||||
const Version = 1
|
||||
|
||||
func init() {
|
||||
llvm.InitializeAllTargets()
|
||||
@@ -781,12 +781,6 @@ 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 {
|
||||
|
||||
+27
-15
@@ -4,6 +4,7 @@ import (
|
||||
"flag"
|
||||
"go/types"
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
@@ -19,19 +20,6 @@ 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)
|
||||
@@ -59,9 +47,7 @@ func TestCompiler(t *testing.T) {
|
||||
"basic.go",
|
||||
"pointer.go",
|
||||
"slice.go",
|
||||
"string.go",
|
||||
"float.go",
|
||||
"interface.go",
|
||||
}
|
||||
|
||||
for _, testCase := range tests {
|
||||
@@ -122,6 +108,8 @@ 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.).
|
||||
@@ -133,6 +121,15 @@ 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
|
||||
}
|
||||
@@ -146,6 +143,12 @@ 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
|
||||
@@ -155,6 +158,15 @@ 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
|
||||
|
||||
+18
-27
@@ -24,7 +24,16 @@ 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)
|
||||
itfTypeCode := b.CreatePtrToInt(itfTypeCodeGlobal, b.uintptrType, "")
|
||||
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, "")
|
||||
itf := llvm.Undef(b.getLLVMRuntimeType("_interface"))
|
||||
itf = b.CreateInsertValue(itf, itfTypeCode, 0, "")
|
||||
itf = b.CreateInsertValue(itf, itfValue, 1, "")
|
||||
@@ -45,7 +54,6 @@ 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())
|
||||
@@ -62,26 +70,15 @@ 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 _, ok := typ.Underlying().(*types.Interface); !ok {
|
||||
methodSet = c.getTypeMethodSet(typ)
|
||||
}
|
||||
if !references.IsNil() || length != 0 || !methodSet.IsNil() {
|
||||
if !references.IsNil() {
|
||||
// Set the 'references' field of the runtime.typecodeID struct.
|
||||
globalValue := llvm.ConstNull(global.Type().ElementType())
|
||||
if !references.IsNil() {
|
||||
globalValue = llvm.ConstInsertValue(globalValue, references, []uint32{0})
|
||||
}
|
||||
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)
|
||||
}
|
||||
@@ -106,8 +103,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(c.ctx.Int32Type(), 0, false),
|
||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
||||
llvm.ConstInt(llvm.Int32Type(), 0, false),
|
||||
llvm.ConstInt(llvm.Int32Type(), 0, false),
|
||||
})
|
||||
fieldGlobalValue = llvm.ConstInsertValue(fieldGlobalValue, fieldName, []uint32{1})
|
||||
if typ.Tag(i) != "" {
|
||||
@@ -115,8 +112,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(c.ctx.Int32Type(), 0, false),
|
||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
||||
llvm.ConstInt(llvm.Int32Type(), 0, false),
|
||||
llvm.ConstInt(llvm.Int32Type(), 0, false),
|
||||
})
|
||||
fieldGlobalValue = llvm.ConstInsertValue(fieldGlobalValue, fieldTag, []uint32{2})
|
||||
}
|
||||
@@ -189,7 +186,7 @@ func getTypeCodeName(t types.Type) string {
|
||||
case *types.Interface:
|
||||
methods := make([]string, t.NumMethods())
|
||||
for i := 0; i < t.NumMethods(); i++ {
|
||||
methods[i] = t.Method(i).Name() + ":" + getTypeCodeName(t.Method(i).Type())
|
||||
methods[i] = getTypeCodeName(t.Method(i).Type())
|
||||
}
|
||||
return "interface:" + "{" + strings.Join(methods, ",") + "}"
|
||||
case *types.Map:
|
||||
@@ -341,16 +338,10 @@ 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")
|
||||
}
|
||||
|
||||
|
||||
@@ -150,9 +150,6 @@ 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())
|
||||
}
|
||||
|
||||
Vendored
-54
@@ -1,54 +0,0 @@
|
||||
// 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()
|
||||
}
|
||||
Vendored
-100
@@ -1,100 +0,0 @@
|
||||
; 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*)
|
||||
Vendored
-16
@@ -7,19 +7,3 @@ 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)
|
||||
}
|
||||
|
||||
Vendored
-67
@@ -19,70 +19,3 @@ 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*)
|
||||
|
||||
Vendored
-21
@@ -1,21 +0,0 @@
|
||||
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
|
||||
}
|
||||
Vendored
-57
@@ -1,57 +0,0 @@
|
||||
; 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*)
|
||||
+20
-72
@@ -155,8 +155,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
// which case this call won't even get to this point but will
|
||||
// already be emitted in initAll.
|
||||
continue
|
||||
case strings.HasPrefix(callFn.name, "runtime.print") || callFn.name == "runtime._panic" || callFn.name == "runtime.hashmapGet":
|
||||
case callFn.name == "(reflect.Type).Elem" || 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.
|
||||
@@ -277,48 +280,26 @@ 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:])
|
||||
}
|
||||
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() {
|
||||
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 {
|
||||
locals[inst.localIndex] = literalValue{uint8(1)}
|
||||
} else {
|
||||
locals[inst.localIndex] = literalValue{uint8(0)}
|
||||
@@ -329,11 +310,11 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
|
||||
}
|
||||
|
||||
// Load various values for the interface implements check below.
|
||||
typecodePtr, err := operands[1].asPointer(r)
|
||||
typeInInterfacePtr, err := operands[1].asPointer(r)
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
methodSetPtr, err := mem.load(typecodePtr.addOffset(r.pointerSize*2), r.pointerSize).asPointer(r)
|
||||
methodSetPtr, err := mem.load(typeInInterfacePtr.addOffset(r.pointerSize), r.pointerSize).asPointer(r)
|
||||
if err != nil {
|
||||
return nil, mem, r.errorAt(inst, err)
|
||||
}
|
||||
@@ -368,39 +349,6 @@ 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
@@ -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.typecodeID" || name == "runtime.funcValueWithSignature" {
|
||||
if name == "runtime.typeInInterface" || name == "runtime.funcValueWithSignature" {
|
||||
uintptrType := ctx.IntType(int(mem.r.pointerSize) * 8)
|
||||
field = llvm.ConstPtrToInt(field, uintptrType)
|
||||
}
|
||||
|
||||
Vendored
+6
-5
@@ -1,16 +1,17 @@
|
||||
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.interfaceMethodInfo* }
|
||||
%runtime.typecodeID = type { %runtime.typecodeID*, i64 }
|
||||
%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, %runtime.interfaceMethodInfo* null }
|
||||
@"reflect/types.type:named:main.foo$id" = external constant i8
|
||||
@"reflect/types.type:named:main.foo" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i64 0 }
|
||||
@"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, i8*, i8*, i8*)
|
||||
declare i1 @runtime.typeAssert(i64, %runtime.typecodeID*, i8*, i8*)
|
||||
|
||||
define void @runtime.initAll() unnamed_addr {
|
||||
entry:
|
||||
@@ -21,7 +22,7 @@ entry:
|
||||
define internal void @main.init() unnamed_addr {
|
||||
entry:
|
||||
; Test type asserts.
|
||||
%typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typecodeID* @"reflect/types.type:named:main.foo" to i64), i8* @"reflect/types.type:named:main.foo$id", i8* undef, i8* null)
|
||||
%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)
|
||||
store i1 %typecode, i1* @main.v1
|
||||
ret void
|
||||
}
|
||||
|
||||
@@ -344,9 +344,8 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
gdb, err := config.Target.LookupGDB()
|
||||
if err != nil {
|
||||
return err
|
||||
if config.Target.GDB == "" {
|
||||
return errors.New("gdb not configured in the target specification")
|
||||
}
|
||||
|
||||
return builder.Build(pkgName, "", config, func(result builder.BuildResult) error {
|
||||
@@ -491,7 +490,7 @@ func FlashGDB(pkgName string, ocdOutput bool, options *compileopts.Options) erro
|
||||
for _, cmd := range gdbCommands {
|
||||
params = append(params, "-ex", cmd)
|
||||
}
|
||||
cmd := executeCommand(config.Options, gdb, params...)
|
||||
cmd := executeCommand(config.Options, config.Target.GDB, params...)
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
+5
-10
@@ -59,10 +59,7 @@ func TestCompiler(t *testing.T) {
|
||||
t.Run("Host", func(t *testing.T) {
|
||||
runPlatTests("", matches, t)
|
||||
if runtime.GOOS == "darwin" {
|
||||
runTest("testdata/libc/filesystem.go", "", t,
|
||||
nil, nil)
|
||||
runTest("testdata/libc/env.go", "", t,
|
||||
[]string{"ENV1=VALUE1", "ENV2=VALUE2"}, nil)
|
||||
runTest("testdata/libc/env.go", "", t, []string{"ENV1=VALUE1", "ENV2=VALUE2"}...)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -110,9 +107,7 @@ func TestCompiler(t *testing.T) {
|
||||
|
||||
t.Run("WASI", func(t *testing.T) {
|
||||
runPlatTests("wasi", matches, t)
|
||||
runTest("testdata/libc/env.go", "wasi", t,
|
||||
[]string{"--env", "ENV1=VALUE1", "--env", "ENV2=VALUE2"}, nil)
|
||||
runTest("testdata/libc/filesystem.go", "wasi", t, nil, []string{"--dir=."})
|
||||
runTest("testdata/libc/env.go", "wasi", t, []string{"ENV1=VALUE1", "ENV2=VALUE2"}...)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -124,7 +119,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, nil, nil)
|
||||
runTest(path, target, t)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -141,7 +136,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, additionalArgs []string) {
|
||||
func runTest(path, target string, t *testing.T, environmentVars ...string) {
|
||||
// Get the expected output for this test.
|
||||
txtpath := path[:len(path)-3] + ".txt"
|
||||
if path[len(path)-1] == os.PathSeparator {
|
||||
@@ -200,7 +195,7 @@ func runTest(path, target string, t *testing.T, environmentVars []string, additi
|
||||
cmd = exec.Command(binary)
|
||||
} else {
|
||||
args := append(spec.Emulator[1:], binary)
|
||||
cmd = exec.Command(spec.Emulator[0], append(args, additionalArgs...)...)
|
||||
cmd = exec.Command(spec.Emulator[0], args...)
|
||||
}
|
||||
|
||||
if len(spec.Emulator) != 0 && spec.Emulator[0] == "wasmtime" {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
type rawState uint8
|
||||
|
||||
//export llvm.coro.resume
|
||||
func coroResume(*rawState)
|
||||
func (s *rawState) resume()
|
||||
|
||||
type state struct{ *rawState }
|
||||
|
||||
@@ -20,7 +20,7 @@ func noopState() *rawState
|
||||
|
||||
// Resume the task until it pauses or completes.
|
||||
func (t *Task) Resume() {
|
||||
coroResume(t.state.rawState)
|
||||
t.state.resume()
|
||||
}
|
||||
|
||||
// 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,
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ const (
|
||||
|
||||
// I2C on the Feather M0.
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: sam.SERCOM3_I2CM,
|
||||
SERCOM: 3,
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func init() {
|
||||
|
||||
// I2C on the Feather M4.
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: sam.SERCOM2_I2CM,
|
||||
SERCOM: 2,
|
||||
}
|
||||
|
||||
@@ -120,22 +120,19 @@ const (
|
||||
|
||||
var (
|
||||
UART1 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART3,
|
||||
TxAltFuncSelector: AF7_USART1_2_3,
|
||||
RxAltFuncSelector: AF7_USART1_2_3,
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART3,
|
||||
AltFuncSelector: AF7_USART1_2_3,
|
||||
}
|
||||
UART2 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART6,
|
||||
TxAltFuncSelector: AF8_USART4_5_6,
|
||||
RxAltFuncSelector: AF8_USART4_5_6,
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART6,
|
||||
AltFuncSelector: AF8_USART4_5_6,
|
||||
}
|
||||
UART3 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART1,
|
||||
TxAltFuncSelector: AF7_USART1_2_3,
|
||||
RxAltFuncSelector: AF7_USART1_2_3,
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART1,
|
||||
AltFuncSelector: AF7_USART1_2_3,
|
||||
}
|
||||
UART0 = UART1
|
||||
)
|
||||
@@ -230,15 +227,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,
|
||||
}
|
||||
|
||||
@@ -10,3 +10,10 @@ var (
|
||||
Bus: sifive.QSPI1,
|
||||
}
|
||||
)
|
||||
|
||||
// I2C on the HiFive1 rev B.
|
||||
var (
|
||||
I2C0 = I2C{
|
||||
Bus: sifive.I2C0,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -75,7 +75,7 @@ const (
|
||||
|
||||
// I2C on the ItsyBitsy M0.
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: sam.SERCOM3_I2CM,
|
||||
SERCOM: 3,
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ func init() {
|
||||
|
||||
// I2C on the ItsyBitsy M4.
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: sam.SERCOM2_I2CM,
|
||||
SERCOM: 2,
|
||||
}
|
||||
|
||||
@@ -54,18 +54,16 @@ var (
|
||||
|
||||
// Console UART (LPUSART1)
|
||||
UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.LPUART1,
|
||||
TxAltFuncSelector: 6,
|
||||
RxAltFuncSelector: 6,
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.LPUART1,
|
||||
AltFuncSelector: 6,
|
||||
}
|
||||
|
||||
// Gps UART
|
||||
UART1 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART1,
|
||||
TxAltFuncSelector: 0,
|
||||
RxAltFuncSelector: 0,
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART1,
|
||||
AltFuncSelector: 0,
|
||||
}
|
||||
|
||||
// SPI
|
||||
|
||||
@@ -13,3 +13,16 @@ 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,
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ const (
|
||||
// USB CDC identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "Makerdiary nRF52840 MDK USB Dongle"
|
||||
usb_STRING_MANUFACTURER = "Nordic Semiconductor ASA"
|
||||
usb_STRING_MANUFACTURER = "Makerdiary"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -39,7 +39,7 @@ const (
|
||||
// USB CDC identifiers
|
||||
const (
|
||||
usb_STRING_PRODUCT = "Makerdiary nRF52840 MDK"
|
||||
usb_STRING_MANUFACTURER = "Nordic Semiconductor ASA"
|
||||
usb_STRING_MANUFACTURER = "Makerdiary"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -33,10 +33,9 @@ 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,
|
||||
TxAltFuncSelector: UART_ALT_FN,
|
||||
RxAltFuncSelector: UART_ALT_FN,
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART3,
|
||||
AltFuncSelector: UART_ALT_FN,
|
||||
}
|
||||
UART1 = &UART0
|
||||
)
|
||||
@@ -54,15 +53,6 @@ const (
|
||||
|
||||
// I2C pins
|
||||
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
|
||||
SCL_PIN = PB6
|
||||
SDA_PIN = PB7
|
||||
)
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// +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)
|
||||
}
|
||||
@@ -33,28 +33,13 @@ 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,
|
||||
TxAltFuncSelector: UART_ALT_FN,
|
||||
RxAltFuncSelector: UART_ALT_FN,
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.LPUART1,
|
||||
AltFuncSelector: 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)
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func init() {
|
||||
|
||||
// I2C on the P1AM-100.
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: sam.SERCOM0_I2CM,
|
||||
SERCOM: 0,
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
// +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
|
||||
)
|
||||
@@ -28,7 +28,7 @@ func init() {
|
||||
|
||||
// I2C on the ItsyBitsy M4.
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: sam.SERCOM2_I2CM,
|
||||
SERCOM: 2,
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ const (
|
||||
|
||||
// I2C on the PyGamer.
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: sam.SERCOM2_I2CM,
|
||||
SERCOM: 2,
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ func init() {
|
||||
|
||||
// I2C on the PyPortal.
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: sam.SERCOM5_I2CM,
|
||||
SERCOM: 5,
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ const (
|
||||
|
||||
// I2C on the QT Py M0.
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: sam.SERCOM2_I2CM,
|
||||
SERCOM: 2,
|
||||
}
|
||||
|
||||
@@ -28,10 +28,9 @@ const (
|
||||
|
||||
var (
|
||||
UART0 = UART{
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART2,
|
||||
TxAltFuncSelector: AF7_USART1_2_3,
|
||||
RxAltFuncSelector: AF7_USART1_2_3,
|
||||
Buffer: NewRingBuffer(),
|
||||
Bus: stm32.USART2,
|
||||
AltFuncSelector: AF7_USART1_2_3,
|
||||
}
|
||||
UART1 = &UART0
|
||||
)
|
||||
@@ -74,7 +73,7 @@ const (
|
||||
)
|
||||
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: stm32.I2C1,
|
||||
AltFuncSelector: AF4_I2C1_2_3,
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ const (
|
||||
|
||||
// I2C on the Trinket M0.
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: sam.SERCOM2_I2CM,
|
||||
SERCOM: 2,
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ const (
|
||||
|
||||
// I2C on the Xiao
|
||||
var (
|
||||
I2C0 = &I2C{
|
||||
I2C0 = I2C{
|
||||
Bus: sam.SERCOM2_I2CM,
|
||||
SERCOM: 2,
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
// +build atmega nrf sam stm32,!stm32l0 fe310 k210
|
||||
// +build avr nrf sam stm32,!stm32f7x2,!stm32l5x2,!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)
|
||||
}
|
||||
|
||||
@@ -9,20 +9,13 @@ 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
|
||||
@@ -49,7 +42,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 {
|
||||
@@ -70,7 +63,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))
|
||||
|
||||
@@ -87,7 +80,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)
|
||||
|
||||
@@ -97,7 +90,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)
|
||||
|
||||
@@ -110,7 +103,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)
|
||||
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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,76 +1560,6 @@ 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
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// +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
|
||||
}
|
||||
@@ -141,3 +141,10 @@ 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{}
|
||||
|
||||
@@ -5,7 +5,6 @@ package machine
|
||||
import (
|
||||
"device/sifive"
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
@@ -186,13 +185,9 @@ 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
|
||||
@@ -201,7 +196,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
|
||||
@@ -233,7 +228,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
|
||||
@@ -281,7 +276,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))
|
||||
|
||||
@@ -300,7 +295,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
|
||||
@@ -311,7 +306,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"device/riscv"
|
||||
"errors"
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func CPUFrequency() uint32 {
|
||||
@@ -494,15 +493,9 @@ 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
|
||||
@@ -511,7 +504,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
|
||||
@@ -525,7 +518,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)
|
||||
@@ -574,7 +567,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.
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"device/nrf"
|
||||
"errors"
|
||||
"runtime/interrupt"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -204,13 +203,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)(unsafe.Pointer(nrf.TWI0))
|
||||
I2C1 = (*I2C)(unsafe.Pointer(nrf.TWI1))
|
||||
I2C0 = I2C{Bus: nrf.TWI0}
|
||||
I2C1 = I2C{Bus: nrf.TWI1}
|
||||
)
|
||||
|
||||
// I2CConfig is used to store config info for I2C.
|
||||
@@ -221,7 +220,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
|
||||
@@ -262,7 +261,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 {
|
||||
@@ -300,7 +299,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 {
|
||||
}
|
||||
@@ -308,7 +307,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 {
|
||||
@@ -321,7 +320,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)
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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,9 +1,8 @@
|
||||
// +build stm32f4 stm32f1
|
||||
// +build stm32,!stm32f7x2,!stm32l5x2,!stm32l0
|
||||
|
||||
package machine
|
||||
|
||||
// I2C implementation for 'older' STM32 MCUs, including the F1 and F4 series
|
||||
// of MCUs.
|
||||
// Peripheral abstraction layer for I2C on the stm32 family
|
||||
|
||||
import (
|
||||
"device/stm32"
|
||||
@@ -29,7 +28,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)
|
||||
@@ -38,18 +37,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++ {
|
||||
@@ -58,7 +57,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++ {
|
||||
@@ -107,7 +106,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
|
||||
@@ -157,7 +156,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
|
||||
@@ -172,7 +171,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
|
||||
@@ -224,7 +223,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
|
||||
@@ -250,7 +249,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
|
||||
@@ -400,7 +399,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)
|
||||
@@ -1,347 +0,0 @@
|
||||
// +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,4 +1,4 @@
|
||||
// +build stm32,!stm32f7x2,!stm32l5x2,!stm32l4x2
|
||||
// +build stm32,!stm32f7x2,!stm32l5x2
|
||||
|
||||
package machine
|
||||
|
||||
|
||||
@@ -13,11 +13,10 @@ import (
|
||||
|
||||
// UART representation
|
||||
type UART struct {
|
||||
Buffer *RingBuffer
|
||||
Bus *stm32.USART_Type
|
||||
Interrupt interrupt.Interrupt
|
||||
TxAltFuncSelector uint8
|
||||
RxAltFuncSelector uint8
|
||||
Buffer *RingBuffer
|
||||
Bus *stm32.USART_Type
|
||||
Interrupt interrupt.Interrupt
|
||||
AltFuncSelector uint8
|
||||
|
||||
// Registers specific to the chip
|
||||
rxReg *volatile.Register32
|
||||
|
||||
@@ -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)(unsafe.Pointer(stm32.I2C1))
|
||||
I2C1 = I2C{Bus: 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
|
||||
}
|
||||
|
||||
@@ -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.TxAltFuncSelector)
|
||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
|
||||
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector)
|
||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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.TxAltFuncSelector)
|
||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
|
||||
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector)
|
||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -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.TxAltFuncSelector)
|
||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
|
||||
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector)
|
||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
|
||||
}
|
||||
|
||||
// UART baudrate calc based on the bus and clockspeed
|
||||
@@ -41,13 +41,3 @@ 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
|
||||
}
|
||||
|
||||
@@ -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.TxAltFuncSelector)
|
||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
|
||||
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector)
|
||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
|
||||
}
|
||||
|
||||
// UART baudrate calc based on the bus and clockspeed
|
||||
|
||||
@@ -1,184 +0,0 @@
|
||||
// +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)
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// +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
|
||||
}
|
||||
@@ -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.TxAltFuncSelector)
|
||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.RxAltFuncSelector)
|
||||
config.TX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTTX}, uart.AltFuncSelector)
|
||||
config.RX.ConfigureAltFunc(PinConfig{Mode: PinModeUARTRX}, uart.AltFuncSelector)
|
||||
}
|
||||
|
||||
// UART baudrate calc based on the bus and clockspeed
|
||||
@@ -39,13 +39,3 @@ 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
@@ -1,4 +1,4 @@
|
||||
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2,!stm32l4x2 fe310 k210 atmega
|
||||
// +build !baremetal stm32,!stm32f7x2,!stm32l5x2 fe310 k210 atmega
|
||||
|
||||
package machine
|
||||
|
||||
|
||||
+3
-39
@@ -2,7 +2,6 @@ package os
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -18,8 +17,9 @@ var (
|
||||
ErrExist = errors.New("file exists")
|
||||
)
|
||||
|
||||
// The following code is copied from the official implementation.
|
||||
// https://github.com/golang/go/blob/4ce6a8e89668b87dce67e2f55802903d6eb9110a/src/os/error.go#L65-L104
|
||||
func IsPermission(err error) bool {
|
||||
return err == ErrPermission
|
||||
}
|
||||
|
||||
func NewSyscallError(syscall string, err error) error {
|
||||
if err == nil {
|
||||
@@ -37,39 +37,3 @@ 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
|
||||
}
|
||||
|
||||
+61
-10
@@ -6,7 +6,6 @@
|
||||
package os
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
@@ -77,7 +76,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 && err != io.EOF {
|
||||
if err != nil {
|
||||
err = &PathError{"read", f.name, err}
|
||||
}
|
||||
return
|
||||
@@ -156,17 +155,59 @@ 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 (
|
||||
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
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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}
|
||||
@@ -192,6 +233,16 @@ 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
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
// +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
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// +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,4 +1,4 @@
|
||||
// +build baremetal wasm,!wasi
|
||||
// +build baremetal wasm
|
||||
|
||||
package os
|
||||
|
||||
|
||||
+1
-5
@@ -1,9 +1,8 @@
|
||||
// +build darwin linux,!baremetal freebsd,!baremetal
|
||||
// +build darwin linux,!baremetal,!wasi freebsd,!baremetal
|
||||
|
||||
package os
|
||||
|
||||
import (
|
||||
"io"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
@@ -78,9 +77,6 @@ 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
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ func Swapper(slice interface{}) func(i, j int) {
|
||||
return func(i, j int) {}
|
||||
}
|
||||
|
||||
typ := v.typecode.Elem()
|
||||
typ := v.Type().Elem()
|
||||
size := typ.Size()
|
||||
|
||||
header := (*SliceHeader)(v.value)
|
||||
|
||||
+47
-274
@@ -122,218 +122,30 @@ func (k Kind) String() string {
|
||||
}
|
||||
|
||||
// basicType returns a new Type for this kind if Kind is a basic type.
|
||||
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
|
||||
func (k Kind) basicType() Type {
|
||||
return Type(k << 1)
|
||||
}
|
||||
|
||||
// The typecode as used in an interface{}.
|
||||
type rawType uintptr
|
||||
type Type uintptr
|
||||
|
||||
func TypeOf(i interface{}) Type {
|
||||
return ValueOf(i).typecode
|
||||
}
|
||||
|
||||
func PtrTo(t Type) Type {
|
||||
ptrType := t.(rawType)<<5 | 5 // 0b0101 == 5
|
||||
ptrType := t<<5 | 5 // 0b0101 == 5
|
||||
if ptrType>>5 != t {
|
||||
panic("reflect: PtrTo type does not fit")
|
||||
}
|
||||
return ptrType
|
||||
}
|
||||
|
||||
func (t rawType) String() string {
|
||||
func (t Type) String() string {
|
||||
return "T"
|
||||
}
|
||||
|
||||
func (t rawType) Kind() Kind {
|
||||
func (t Type) Kind() Kind {
|
||||
if t%2 == 0 {
|
||||
// basic type
|
||||
return Kind((t >> 1) % 32)
|
||||
@@ -344,18 +156,14 @@ func (t rawType) 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 rawType) Elem() Type {
|
||||
return t.elem()
|
||||
}
|
||||
|
||||
func (t rawType) elem() rawType {
|
||||
func (t Type) Elem() Type {
|
||||
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 rawType(elem)
|
||||
return Type(elem)
|
||||
default: // not implemented: Map
|
||||
panic("unimplemented: (reflect.Type).Elem()")
|
||||
}
|
||||
@@ -367,14 +175,14 @@ func (t rawType) elem() rawType {
|
||||
// simply shifted off.
|
||||
//
|
||||
// The behavior is only defined for non-basic types.
|
||||
func (t rawType) stripPrefix() rawType {
|
||||
func (t Type) stripPrefix() Type {
|
||||
// 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 rawType(n)
|
||||
return Type(n)
|
||||
}
|
||||
// Not a named type, so the value is stored directly in the type code.
|
||||
return t >> 5
|
||||
@@ -382,23 +190,7 @@ func (t rawType) stripPrefix() rawType {
|
||||
|
||||
// Field returns the type of the i'th field of this struct type. It panics if t
|
||||
// is not a struct type.
|
||||
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 {
|
||||
func (t Type) Field(i int) StructField {
|
||||
if t.Kind() != Struct {
|
||||
panic(&TypeError{"Field"})
|
||||
}
|
||||
@@ -414,7 +206,7 @@ func (t rawType) rawField(i int) rawStructField {
|
||||
// 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 := rawStructField{}
|
||||
field := StructField{}
|
||||
offset := uintptr(0)
|
||||
for fieldNum := 0; fieldNum <= i; fieldNum++ {
|
||||
// Read some flags of this field, like whether the field is an
|
||||
@@ -423,16 +215,15 @@ func (t rawType) rawField(i int) rawStructField {
|
||||
p = unsafe.Pointer(uintptr(p) + 1)
|
||||
|
||||
// Read the type of this struct field.
|
||||
var fieldTypeVal uintptr
|
||||
fieldTypeVal, p = readVarint(p)
|
||||
fieldType := rawType(fieldTypeVal)
|
||||
field.Type = fieldType
|
||||
var fieldType uintptr
|
||||
fieldType, p = readVarint(p)
|
||||
field.Type = Type(fieldType)
|
||||
|
||||
// Move Offset forward to align it to this field's alignment.
|
||||
// Assume alignment is a power of two.
|
||||
offset = align(offset, uintptr(fieldType.Align()))
|
||||
offset = align(offset, uintptr(field.Type.Align()))
|
||||
field.Offset = offset
|
||||
offset += fieldType.Size() // starting (unaligned) offset for next field
|
||||
offset += field.Type.Size() // starting (unaligned) offset for next field
|
||||
|
||||
// Read the field name.
|
||||
var nameNum uintptr
|
||||
@@ -473,7 +264,7 @@ func (t rawType) rawField(i int) rawStructField {
|
||||
// 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 rawType) Bits() int {
|
||||
func (t Type) Bits() int {
|
||||
kind := t.Kind()
|
||||
if kind >= Int && kind <= Complex128 {
|
||||
return int(t.Size()) * 8
|
||||
@@ -483,7 +274,7 @@ func (t rawType) Bits() int {
|
||||
|
||||
// Len returns the number of elements in this array. It panics of the type kind
|
||||
// is not Array.
|
||||
func (t rawType) Len() int {
|
||||
func (t Type) Len() int {
|
||||
if t.Kind() != Array {
|
||||
panic(TypeError{"Len"})
|
||||
}
|
||||
@@ -499,7 +290,7 @@ func (t rawType) Len() int {
|
||||
|
||||
// NumField returns the number of fields of a struct type. It panics for other
|
||||
// type kinds.
|
||||
func (t rawType) NumField() int {
|
||||
func (t Type) NumField() int {
|
||||
if t.Kind() != Struct {
|
||||
panic(&TypeError{"NumField"})
|
||||
}
|
||||
@@ -510,7 +301,7 @@ func (t rawType) NumField() int {
|
||||
|
||||
// Size returns the size in bytes of a given type. It is similar to
|
||||
// unsafe.Sizeof.
|
||||
func (t rawType) Size() uintptr {
|
||||
func (t Type) Size() uintptr {
|
||||
switch t.Kind() {
|
||||
case Bool, Int8, Uint8:
|
||||
return 1
|
||||
@@ -533,24 +324,21 @@ func (t rawType) Size() uintptr {
|
||||
case Complex128:
|
||||
return 16
|
||||
case String:
|
||||
return unsafe.Sizeof("")
|
||||
return unsafe.Sizeof(StringHeader{})
|
||||
case UnsafePointer, Chan, Map, Ptr:
|
||||
return unsafe.Sizeof(uintptr(0))
|
||||
case Slice:
|
||||
return unsafe.Sizeof([]int{})
|
||||
return unsafe.Sizeof(SliceHeader{})
|
||||
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.rawField(numField - 1)
|
||||
lastField := t.Field(numField - 1)
|
||||
return lastField.Offset + lastField.Type.Size()
|
||||
default:
|
||||
panic("unimplemented: size of type")
|
||||
@@ -559,7 +347,7 @@ func (t rawType) Size() uintptr {
|
||||
|
||||
// Align returns the alignment of this type. It is similar to calling
|
||||
// unsafe.Alignof.
|
||||
func (t rawType) Align() int {
|
||||
func (t Type) Align() int {
|
||||
switch t.Kind() {
|
||||
case Bool, Int8, Uint8:
|
||||
return int(unsafe.Alignof(int8(0)))
|
||||
@@ -582,28 +370,25 @@ func (t rawType) Align() int {
|
||||
case Complex128:
|
||||
return int(unsafe.Alignof(complex128(0)))
|
||||
case String:
|
||||
return int(unsafe.Alignof(""))
|
||||
return int(unsafe.Alignof(StringHeader{}))
|
||||
case UnsafePointer, Chan, Map, Ptr:
|
||||
return int(unsafe.Alignof(uintptr(0)))
|
||||
case Slice:
|
||||
return int(unsafe.Alignof([]int(nil)))
|
||||
return int(unsafe.Alignof(SliceHeader{}))
|
||||
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.rawField(i).Type.Align()
|
||||
fieldAlignment := t.Field(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")
|
||||
}
|
||||
@@ -611,31 +396,31 @@ func (t rawType) 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 rawType) FieldAlign() int {
|
||||
func (t Type) FieldAlign() int {
|
||||
return t.Align()
|
||||
}
|
||||
|
||||
// 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) {
|
||||
// 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 {
|
||||
return true
|
||||
}
|
||||
if u.Kind() == Interface {
|
||||
panic("reflect: unimplemented: AssignableTo with interface")
|
||||
if t.Kind() == Interface {
|
||||
panic("reflect: unimplemented: assigning to interface of different type")
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (t rawType) Implements(u Type) bool {
|
||||
if u.Kind() != Interface {
|
||||
func (t Type) Implements(u Type) bool {
|
||||
if t.Kind() != Interface {
|
||||
panic("reflect: non-interface type passed to Type.Implements")
|
||||
}
|
||||
return t.AssignableTo(u)
|
||||
return u.AssignableTo(t)
|
||||
}
|
||||
|
||||
// Comparable returns whether values of this type can be compared to each other.
|
||||
func (t rawType) Comparable() bool {
|
||||
func (t Type) Comparable() bool {
|
||||
switch t.Kind() {
|
||||
case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||
return true
|
||||
@@ -654,7 +439,7 @@ func (t rawType) Comparable() bool {
|
||||
case Slice:
|
||||
return false
|
||||
case Array:
|
||||
return t.elem().Comparable()
|
||||
return t.Elem().Comparable()
|
||||
case Func:
|
||||
return false
|
||||
case Map:
|
||||
@@ -662,7 +447,7 @@ func (t rawType) Comparable() bool {
|
||||
case Struct:
|
||||
numField := t.NumField()
|
||||
for i := 0; i < numField; i++ {
|
||||
if !t.rawField(i).Type.Comparable() {
|
||||
if !t.Field(i).Type.Comparable() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@@ -672,19 +457,19 @@ func (t rawType) Comparable() bool {
|
||||
}
|
||||
}
|
||||
|
||||
func (t rawType) ConvertibleTo(u Type) bool {
|
||||
func (t Type) ConvertibleTo(u Type) bool {
|
||||
panic("unimplemented: (reflect.Type).ConvertibleTo()")
|
||||
}
|
||||
|
||||
func (t rawType) NumMethod() int {
|
||||
func (t Type) NumMethod() int {
|
||||
panic("unimplemented: (reflect.Type).NumMethod()")
|
||||
}
|
||||
|
||||
func (t rawType) Name() string {
|
||||
func (t Type) Name() string {
|
||||
panic("unimplemented: (reflect.Type).Name()")
|
||||
}
|
||||
|
||||
func (t rawType) Key() Type {
|
||||
func (t Type) Key() Type {
|
||||
panic("unimplemented: (reflect.Type).Key()")
|
||||
}
|
||||
|
||||
@@ -703,18 +488,6 @@ 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
|
||||
|
||||
|
||||
+32
-75
@@ -16,7 +16,7 @@ const (
|
||||
)
|
||||
|
||||
type Value struct {
|
||||
typecode rawType
|
||||
typecode Type
|
||||
value unsafe.Pointer
|
||||
flags valueFlags
|
||||
}
|
||||
@@ -28,13 +28,6 @@ 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
|
||||
@@ -43,10 +36,10 @@ func Indirect(v Value) Value {
|
||||
}
|
||||
|
||||
//go:linkname composeInterface runtime.composeInterface
|
||||
func composeInterface(rawType, unsafe.Pointer) interface{}
|
||||
func composeInterface(Type, unsafe.Pointer) interface{}
|
||||
|
||||
//go:linkname decomposeInterface runtime.decomposeInterface
|
||||
func decomposeInterface(i interface{}) (rawType, unsafe.Pointer)
|
||||
func decomposeInterface(i interface{}) (Type, unsafe.Pointer)
|
||||
|
||||
func ValueOf(i interface{}) Value {
|
||||
typecode, value := decomposeInterface(i)
|
||||
@@ -58,20 +51,11 @@ func ValueOf(i interface{}) Value {
|
||||
}
|
||||
|
||||
func (v Value) Interface() interface{} {
|
||||
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)) {
|
||||
if v.isIndirect() && v.Type().Size() <= unsafe.Sizeof(uintptr(0)) {
|
||||
// Value was indirect but must be put back directly in the interface
|
||||
// value.
|
||||
var value uintptr
|
||||
for j := v.typecode.Size(); j != 0; j-- {
|
||||
for j := v.Type().Size(); j != 0; j-- {
|
||||
value = (value << 8) | uintptr(*(*uint8)(unsafe.Pointer(uintptr(v.value) + j - 1)))
|
||||
}
|
||||
v.value = unsafe.Pointer(value)
|
||||
@@ -83,16 +67,8 @@ 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.typecode.Kind()
|
||||
return v.Type().Kind()
|
||||
}
|
||||
|
||||
// IsNil returns whether the value is the nil value. It panics if the value Kind
|
||||
@@ -156,7 +132,7 @@ func (v Value) CanInterface() bool {
|
||||
}
|
||||
|
||||
func (v Value) CanAddr() bool {
|
||||
return v.flags&(valueFlagIndirect) == valueFlagIndirect
|
||||
panic("unimplemented: (reflect.Value).CanAddr()")
|
||||
}
|
||||
|
||||
func (v Value) Addr() Value {
|
||||
@@ -337,9 +313,10 @@ 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 {
|
||||
switch v.typecode.Kind() {
|
||||
t := v.Type()
|
||||
switch t.Kind() {
|
||||
case Array:
|
||||
return v.typecode.Len()
|
||||
return v.Type().Len()
|
||||
case Chan:
|
||||
return chanlen(v.value)
|
||||
case Map:
|
||||
@@ -359,9 +336,10 @@ 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 {
|
||||
switch v.typecode.Kind() {
|
||||
t := v.Type()
|
||||
switch t.Kind() {
|
||||
case Array:
|
||||
return v.typecode.Len()
|
||||
return v.Type().Len()
|
||||
case Chan:
|
||||
return chancap(v.value)
|
||||
case Slice:
|
||||
@@ -374,7 +352,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.typecode.NumField()
|
||||
return v.Type().NumField()
|
||||
}
|
||||
|
||||
func (v Value) Elem() Value {
|
||||
@@ -388,7 +366,7 @@ func (v Value) Elem() Value {
|
||||
return Value{}
|
||||
}
|
||||
return Value{
|
||||
typecode: v.typecode.elem(),
|
||||
typecode: v.Type().Elem(),
|
||||
value: ptr,
|
||||
flags: v.flags | valueFlagIndirect,
|
||||
}
|
||||
@@ -399,7 +377,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.typecode.rawField(i)
|
||||
structField := v.Type().Field(i)
|
||||
flags := v.flags
|
||||
if structField.PkgPath != "" {
|
||||
// The fact that PkgPath is present means that this field is not
|
||||
@@ -407,15 +385,14 @@ func (v Value) Field(i int) Value {
|
||||
flags &^= valueFlagExported
|
||||
}
|
||||
|
||||
size := v.typecode.Size()
|
||||
fieldType := structField.Type
|
||||
fieldSize := fieldType.Size()
|
||||
size := v.Type().Size()
|
||||
fieldSize := structField.Type.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: fieldType,
|
||||
typecode: structField.Type,
|
||||
value: unsafe.Pointer(uintptr(v.value) + structField.Offset),
|
||||
}
|
||||
}
|
||||
@@ -430,7 +407,7 @@ func (v Value) Field(i int) Value {
|
||||
// situation explicitly.
|
||||
return Value{
|
||||
flags: flags,
|
||||
typecode: fieldType,
|
||||
typecode: structField.Type,
|
||||
value: unsafe.Pointer(uintptr(0)),
|
||||
}
|
||||
}
|
||||
@@ -443,7 +420,7 @@ func (v Value) Field(i int) Value {
|
||||
value := unsafe.Pointer(loadValue(ptr, fieldSize))
|
||||
return Value{
|
||||
flags: 0,
|
||||
typecode: fieldType,
|
||||
typecode: structField.Type,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
@@ -453,7 +430,7 @@ func (v Value) Field(i int) Value {
|
||||
value := maskAndShift(uintptr(v.value), structField.Offset, fieldSize)
|
||||
return Value{
|
||||
flags: flags,
|
||||
typecode: fieldType,
|
||||
typecode: structField.Type,
|
||||
value: unsafe.Pointer(value),
|
||||
}
|
||||
}
|
||||
@@ -467,10 +444,10 @@ func (v Value) Index(i int) Value {
|
||||
panic("reflect: slice index out of range")
|
||||
}
|
||||
elem := Value{
|
||||
typecode: v.typecode.elem(),
|
||||
typecode: v.Type().Elem(),
|
||||
flags: v.flags | valueFlagIndirect,
|
||||
}
|
||||
addr := uintptr(slice.Data) + elem.typecode.Size()*uintptr(i) // pointer to new value
|
||||
addr := uintptr(slice.Data) + elem.Type().Size()*uintptr(i) // pointer to new value
|
||||
elem.value = unsafe.Pointer(addr)
|
||||
return elem
|
||||
case String:
|
||||
@@ -487,13 +464,13 @@ func (v Value) Index(i int) Value {
|
||||
}
|
||||
case Array:
|
||||
// Extract an element from the array.
|
||||
elemType := v.typecode.elem()
|
||||
elemType := v.Type().Elem()
|
||||
elemSize := elemType.Size()
|
||||
size := v.typecode.Size()
|
||||
size := v.Type().Size()
|
||||
if size == 0 {
|
||||
// The element size is 0 and/or the length of the array is 0.
|
||||
return Value{
|
||||
typecode: v.typecode.elem(),
|
||||
typecode: v.Type().Elem(),
|
||||
flags: v.flags,
|
||||
}
|
||||
}
|
||||
@@ -504,7 +481,7 @@ func (v Value) Index(i int) Value {
|
||||
// elemSize.
|
||||
addr := uintptr(v.value) + elemSize*uintptr(i) // pointer to new value
|
||||
return Value{
|
||||
typecode: v.typecode.elem(),
|
||||
typecode: v.Type().Elem(),
|
||||
flags: v.flags,
|
||||
value: unsafe.Pointer(addr),
|
||||
}
|
||||
@@ -515,7 +492,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.typecode.elem(),
|
||||
typecode: v.Type().Elem(),
|
||||
flags: v.flags,
|
||||
value: unsafe.Pointer(loadValue(unsafe.Pointer(addr), elemSize)),
|
||||
}
|
||||
@@ -526,7 +503,7 @@ func (v Value) Index(i int) Value {
|
||||
offset := elemSize * uintptr(i)
|
||||
value := maskAndShift(uintptr(v.value), offset, elemSize)
|
||||
return Value{
|
||||
typecode: v.typecode.elem(),
|
||||
typecode: v.Type().Elem(),
|
||||
flags: v.flags,
|
||||
value: unsafe.Pointer(value),
|
||||
}
|
||||
@@ -555,14 +532,6 @@ 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()")
|
||||
}
|
||||
@@ -592,10 +561,10 @@ func (it *MapIter) Next() bool {
|
||||
|
||||
func (v Value) Set(x Value) {
|
||||
v.checkAddressable()
|
||||
if !v.typecode.AssignableTo(x.typecode) {
|
||||
if !v.Type().AssignableTo(x.Type()) {
|
||||
panic("reflect: cannot set")
|
||||
}
|
||||
size := v.typecode.Size()
|
||||
size := v.Type().Size()
|
||||
xptr := x.value
|
||||
if size <= unsafe.Sizeof(uintptr(0)) && !x.isIndirect() {
|
||||
value := x.value
|
||||
@@ -686,18 +655,6 @@ 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")
|
||||
|
||||
+9
-16
@@ -349,55 +349,48 @@ 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.RawType() == 0 {
|
||||
if x.Type() == 0 {
|
||||
return 0 // nil interface
|
||||
}
|
||||
|
||||
value := (*_interface)(unsafe.Pointer(&itf)).value
|
||||
ptr := value
|
||||
if x.RawType().Size() <= unsafe.Sizeof(uintptr(0)) {
|
||||
if x.Type().Size() <= unsafe.Sizeof(uintptr(0)) {
|
||||
// Value fits in pointer, so it's directly stored in the pointer.
|
||||
ptr = unsafe.Pointer(&value)
|
||||
}
|
||||
|
||||
switch x.RawType().Kind() {
|
||||
switch x.Type().Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return hashmapHash(ptr, x.RawType().Size())
|
||||
return hashmapHash(ptr, x.Type().Size())
|
||||
case reflect.Bool, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return hashmapHash(ptr, x.RawType().Size())
|
||||
return hashmapHash(ptr, x.Type().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.RawType().Size())
|
||||
return hashmapHash(ptr, x.Type().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.RawType().Size())
|
||||
return hashmapHash(ptr, x.Type().Size())
|
||||
case reflect.Array:
|
||||
var hash uint32
|
||||
for i := 0; i < x.Len(); i++ {
|
||||
hash |= hashmapInterfaceHash(valueInterfaceUnsafe(x.Index(i)))
|
||||
hash |= hashmapInterfaceHash(x.Index(i).Interface())
|
||||
}
|
||||
return hash
|
||||
case reflect.Struct:
|
||||
var hash uint32
|
||||
for i := 0; i < x.NumField(); i++ {
|
||||
hash |= hashmapInterfaceHash(valueInterfaceUnsafe(x.Field(i)))
|
||||
hash |= hashmapInterfaceHash(x.Field(i).Interface())
|
||||
}
|
||||
return hash
|
||||
default:
|
||||
|
||||
+14
-10
@@ -31,21 +31,18 @@ func interfaceEqual(x, y interface{}) bool {
|
||||
}
|
||||
|
||||
func reflectValueEqual(x, y reflect.Value) bool {
|
||||
// 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 {
|
||||
if x.Type() == 0 || y.Type() == 0 {
|
||||
// One of them is nil.
|
||||
return x.RawType() == y.RawType()
|
||||
return x.Type() == y.Type()
|
||||
}
|
||||
|
||||
if x.RawType() != y.RawType() {
|
||||
if x.Type() != y.Type() {
|
||||
// The type is not the same, which means the interfaces are definitely
|
||||
// not the same.
|
||||
return false
|
||||
}
|
||||
|
||||
switch x.RawType().Kind() {
|
||||
switch x.Type().Kind() {
|
||||
case reflect.Bool:
|
||||
return x.Bool() == y.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
@@ -110,8 +107,6 @@ 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
|
||||
@@ -123,11 +118,20 @@ 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 *uint8) bool
|
||||
func typeAssert(actualType uintptr, assertedType *typecodeID) bool
|
||||
|
||||
// Pseudo function call that returns whether a given type implements all methods
|
||||
// of the given interface.
|
||||
|
||||
@@ -56,7 +56,6 @@ func nanosecondsToTicks(ns int64) timeUnit {
|
||||
}
|
||||
|
||||
// number of ticks (microseconds) since start.
|
||||
//go:linkname ticks runtime.ticks
|
||||
func ticks() timeUnit {
|
||||
return timeUnit(tickCount.Get())
|
||||
}
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
// +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
|
||||
}
|
||||
@@ -8,16 +8,11 @@ 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()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// +build !wasi,!darwin
|
||||
|
||||
package syscall
|
||||
|
||||
func (e Errno) Is(target error) bool { return false }
|
||||
@@ -13,15 +13,12 @@ type sliceHeader struct {
|
||||
}
|
||||
|
||||
func Close(fd int) (err error) {
|
||||
if libc_close(fd) < 0 {
|
||||
err = getErrno()
|
||||
}
|
||||
return
|
||||
return ENOSYS // TODO
|
||||
}
|
||||
|
||||
func Write(fd int, p []byte) (n int, err error) {
|
||||
buf, count := splitSlice(p)
|
||||
n = libc_write(fd, buf, uint(count))
|
||||
n = libc_write(int32(fd), buf, uint(count))
|
||||
if n < 0 {
|
||||
err = getErrno()
|
||||
}
|
||||
@@ -29,25 +26,15 @@ func Write(fd int, p []byte) (n int, err error) {
|
||||
}
|
||||
|
||||
func Read(fd int, p []byte) (n int, err error) {
|
||||
buf, count := splitSlice(p)
|
||||
n = libc_read(fd, buf, uint(count))
|
||||
if n < 0 {
|
||||
err = getErrno()
|
||||
}
|
||||
return
|
||||
return 0, ENOSYS // TODO
|
||||
}
|
||||
|
||||
func Seek(fd int, offset int64, whence int) (off int64, 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 Open(path string, mode int, perm uint32) (fd int, err error) {
|
||||
return 0, ENOSYS // TODO
|
||||
}
|
||||
|
||||
func Mkdir(path string, mode uint32) (err error) {
|
||||
@@ -91,20 +78,8 @@ 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 int, buf *byte, count uint) int
|
||||
func libc_write(fd int32, 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
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// +build darwin
|
||||
|
||||
package syscall
|
||||
|
||||
// This file defines errno and constants to match the darwin libsystem ABI.
|
||||
@@ -24,25 +22,10 @@ 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
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
package syscall
|
||||
|
||||
import "errors"
|
||||
|
||||
// A Signal is a number describing a process signal.
|
||||
// It implements the os.Signal interface.
|
||||
type Signal int
|
||||
@@ -30,6 +32,7 @@ const (
|
||||
O_RDWR = 2
|
||||
|
||||
O_CREAT = 0100
|
||||
O_CREATE = O_CREAT
|
||||
O_TRUNC = 01000
|
||||
O_APPEND = 02000
|
||||
O_EXCL = 0200
|
||||
@@ -38,9 +41,8 @@ const (
|
||||
O_CLOEXEC = 0
|
||||
)
|
||||
|
||||
//go:extern errno
|
||||
var libcErrno uintptr
|
||||
var dummyError = errors.New("unknown syscall error")
|
||||
|
||||
func getErrno() error {
|
||||
return Errno(libcErrno)
|
||||
return dummyError
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ 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
|
||||
@@ -47,95 +48,3 @@ 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. */
|
||||
)
|
||||
|
||||
@@ -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
|
||||
// +build baremetal nintendoswitch wasi
|
||||
|
||||
package syscall
|
||||
|
||||
|
||||
+1
-1
@@ -19,5 +19,5 @@
|
||||
"src/internal/task/task_stack_avr.S",
|
||||
"src/runtime/gc_avr.S"
|
||||
],
|
||||
"gdb": ["avr-gdb"]
|
||||
"gdb": "avr-gdb"
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"inherits": ["cortex-m"],
|
||||
"llvm-target": "armv7m-none-eabi",
|
||||
"build-tags": ["bluepill", "stm32f103", "stm32f1", "stm32"],
|
||||
"build-tags": ["bluepill", "stm32f103", "stm32"],
|
||||
"cflags": [
|
||||
"--target=armv7m-none-eabi",
|
||||
"-Qunused-arguments"
|
||||
|
||||
@@ -28,5 +28,5 @@
|
||||
"src/internal/task/task_stack_cortexm.S",
|
||||
"src/runtime/gc_arm.S"
|
||||
],
|
||||
"gdb": ["gdb-multiarch", "arm-none-eabi-gdb"]
|
||||
"gdb": "gdb-multiarch"
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
"llvm-target": "armv7em-none-eabi",
|
||||
"cflags": [
|
||||
"--target=armv7em-none-eabi",
|
||||
"-mfloat-abi=soft",
|
||||
"-Qunused-arguments"
|
||||
"-mfloat-abi=soft"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -4,5 +4,6 @@
|
||||
"cflags": [
|
||||
"--target=armv7em-none-eabi",
|
||||
"-Qunused-arguments"
|
||||
]
|
||||
],
|
||||
"gdb": "arm-none-eabi-gdb"
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user