mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-21 12:59:04 +00:00
Merge remote-tracking branch 'origin/dev' into dev
This commit is contained in:
@@ -1,3 +1,69 @@
|
|||||||
|
0.19.0
|
||||||
|
---
|
||||||
|
|
||||||
|
* **command line**
|
||||||
|
- don't consider compile-only tests as failing
|
||||||
|
- add -test flag for `tinygo list`
|
||||||
|
- escape commands while printing them with the -x flag
|
||||||
|
- make flash-command portable and safer to use
|
||||||
|
- use `extended-remote` instead of `remote` in GDB
|
||||||
|
- detect specific serial port IDs based on USB vid/pid
|
||||||
|
- add a flag to the command line to select the serial implementation
|
||||||
|
* **compiler**
|
||||||
|
- `cgo`: improve constant parser
|
||||||
|
- `compiler`: support chained interrupt handlers
|
||||||
|
- `compiler`: add support for running a builtin in a goroutine
|
||||||
|
- `compiler`: do not emit nil checks for loading closure variables
|
||||||
|
- `compiler`: skip context parameter when starting regular goroutine
|
||||||
|
- `compiler`: refactor method names
|
||||||
|
- `compiler`: add function and global section pragmas
|
||||||
|
- `compiler`: implement `syscall.rawSyscallNoError` in inline assembly
|
||||||
|
- `interp`: ignore inline assembly in markExternal
|
||||||
|
- `interp`: fix a bug in pointer cast workaround
|
||||||
|
- `loader`: fix testing a main package
|
||||||
|
* **standard library**
|
||||||
|
- `crypto/rand`: replace this package with a TinyGo version
|
||||||
|
- `machine`: make USBCDC global a pointer
|
||||||
|
- `machine`: make UART objects pointer receivers
|
||||||
|
- `machine`: define Serial as the default output
|
||||||
|
- `net`: add initial support for net.IP
|
||||||
|
- `net`: add more net compatibility
|
||||||
|
- `os`: add stub for os.ReadDir
|
||||||
|
- `os`: add FileMode constants from Go 1.16
|
||||||
|
- `os`: add stubs required for net/http
|
||||||
|
- `os`: implement process related functions
|
||||||
|
- `reflect`: implement AppendSlice
|
||||||
|
- `reflect`: add stubs required for net/http
|
||||||
|
- `runtime`: make task.Data a 64-bit integer to avoid overflow
|
||||||
|
- `runtime`: expose memory stats
|
||||||
|
- `sync`: implement NewCond
|
||||||
|
- `syscall`: fix int type in libc version
|
||||||
|
* **targets**
|
||||||
|
- `cortexm`: do not disable interrupts on abort
|
||||||
|
- `cortexm`: bump default stack size to 2048 bytes
|
||||||
|
- `nrf`: avoid heap allocation in waitForEvent
|
||||||
|
- `nrf`: don't trigger a heap allocation in SPI.Transfer
|
||||||
|
- `nrf52840`: add support for flashing with the BOSSA tool
|
||||||
|
- `rp2040`: add support for GPIO input
|
||||||
|
- `rp2040`: add basic support for ADC
|
||||||
|
- `rp2040`: gpio and adc pin definitions
|
||||||
|
- `rp2040`: implement UART
|
||||||
|
- `rp2040`: patch elf to checksum 2nd stage boot
|
||||||
|
- `stm32`: add PWM for most chips
|
||||||
|
- `stm32`: add support for pin interrupts
|
||||||
|
- `stm32f103`: add support for PinInputPullup / PinInputPulldown
|
||||||
|
- `wasi`: remove wasm build tag
|
||||||
|
* **boards**
|
||||||
|
- `feather-rp2040`: add support for this board
|
||||||
|
- `feather-nrf52840-sense`: add board definition for this board
|
||||||
|
- `pca10059`: support flashing from Windows
|
||||||
|
- `nano-rp2040`: add this board
|
||||||
|
- `nano-33-ble`: add support for this board
|
||||||
|
- `pico`: add the Raspberry Pi Pico board with the new RP2040 chip
|
||||||
|
- `qtpy`: add pin for neopixels
|
||||||
|
- all: add definition for ws2812 for supported boards
|
||||||
|
|
||||||
|
|
||||||
0.18.0
|
0.18.0
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -336,6 +336,8 @@ smoketest:
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=feather-nrf52840-sense examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=itsybitsy-nrf52840 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=itsybitsy-nrf52840 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=qtpy examples/serial
|
$(TINYGO) build -size short -o test.hex -target=qtpy examples/serial
|
||||||
@@ -356,7 +358,11 @@ smoketest:
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=arduino-nano33 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=arduino-nano33 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pico examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=pico examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=nano-33-ble examples/blinky1
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=nano-rp2040 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=feather-rp2040 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
@@ -432,6 +438,8 @@ endif
|
|||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=1 examples/blinky1
|
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=1 examples/blinky1
|
||||||
@$(MD5SUM) test.hex
|
@$(MD5SUM) test.hex
|
||||||
|
$(TINYGO) build -size short -o test.hex -target=pca10040 -serial=none examples/echo
|
||||||
|
@$(MD5SUM) test.hex
|
||||||
$(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
|
$(TINYGO) build -o test.nro -target=nintendoswitch examples/serial
|
||||||
@$(MD5SUM) test.nro
|
@$(MD5SUM) test.nro
|
||||||
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
|
$(TINYGO) build -size short -o test.hex -target=pca10040 -opt=0 ./testdata/stdlib.go
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ See the [getting started instructions](https://tinygo.org/getting-started/) for
|
|||||||
|
|
||||||
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
You can compile TinyGo programs for microcontrollers, WebAssembly and Linux.
|
||||||
|
|
||||||
The following 63 microcontroller boards are currently supported:
|
The following 68 microcontroller boards are currently supported:
|
||||||
|
|
||||||
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
* [Adafruit Circuit Playground Bluefruit](https://www.adafruit.com/product/4333)
|
||||||
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
* [Adafruit Circuit Playground Express](https://www.adafruit.com/product/3333)
|
||||||
@@ -52,6 +52,7 @@ The following 63 microcontroller boards are currently supported:
|
|||||||
* [Adafruit Feather M4](https://www.adafruit.com/product/3857)
|
* [Adafruit Feather M4](https://www.adafruit.com/product/3857)
|
||||||
* [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759)
|
* [Adafruit Feather M4 CAN](https://www.adafruit.com/product/4759)
|
||||||
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
|
* [Adafruit Feather nRF52840 Express](https://www.adafruit.com/product/4062)
|
||||||
|
* [Adafruit Feather nRF52840 Sense](https://www.adafruit.com/product/4516)
|
||||||
* [Adafruit Feather RP2040](https://www.adafruit.com/product/4884)
|
* [Adafruit Feather RP2040](https://www.adafruit.com/product/4884)
|
||||||
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
|
* [Adafruit Feather STM32F405 Express](https://www.adafruit.com/product/4382)
|
||||||
* [Adafruit Grand Central M4](https://www.adafruit.com/product/4064)
|
* [Adafruit Grand Central M4](https://www.adafruit.com/product/4064)
|
||||||
@@ -69,7 +70,10 @@ The following 63 microcontroller boards are currently supported:
|
|||||||
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
|
* [Arduino Mega 2560](https://store.arduino.cc/arduino-mega-2560-rev3)
|
||||||
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
|
* [Arduino MKR1000](https://store.arduino.cc/arduino-mkr1000-wifi)
|
||||||
* [Arduino Nano](https://store.arduino.cc/arduino-nano)
|
* [Arduino Nano](https://store.arduino.cc/arduino-nano)
|
||||||
* [Arduino Nano33 IoT](https://store.arduino.cc/nano-33-iot)
|
* [Arduino Nano 33 BLE](https://store.arduino.cc/nano-33-ble)
|
||||||
|
* [Arduino Nano 33 BLE Sense](https://store.arduino.cc/nano-33-ble-sense)
|
||||||
|
* [Arduino Nano 33 IoT](https://store.arduino.cc/nano-33-iot)
|
||||||
|
* [Arduino Nano RP2040 Connect](https://store.arduino.cc/nano-rp2040-connect)
|
||||||
* [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3)
|
* [Arduino Uno](https://store.arduino.cc/arduino-uno-rev3)
|
||||||
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
|
* [Arduino Zero](https://store.arduino.cc/usa/arduino-zero)
|
||||||
* [BBC micro:bit](https://microbit.org/)
|
* [BBC micro:bit](https://microbit.org/)
|
||||||
@@ -96,6 +100,7 @@ The following 63 microcontroller boards are currently supported:
|
|||||||
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
|
* [PJRC Teensy 3.6](https://www.pjrc.com/store/teensy36.html)
|
||||||
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
|
* [PJRC Teensy 4.0](https://www.pjrc.com/store/teensy40.html)
|
||||||
* [ProductivityOpen P1AM-100](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html)
|
* [ProductivityOpen P1AM-100](https://facts-engineering.github.io/modules/P1AM-100/P1AM-100.html)
|
||||||
|
* [Raspberry Pi Pico](https://www.raspberrypi.org/products/raspberry-pi-pico/)
|
||||||
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
|
* [Seeed Wio Terminal](https://www.seeedstudio.com/Wio-Terminal-p-4509.html)
|
||||||
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
|
* [Seeed Seeeduino XIAO](https://www.seeedstudio.com/Seeeduino-XIAO-Arduino-Microcontroller-SAMD21-Cortex-M0+-p-4426.html)
|
||||||
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
|
* [Seeed Sipeed MAix BiT](https://www.seeedstudio.com/Sipeed-MAix-BiT-for-RISC-V-AI-IoT-p-2872.html)
|
||||||
|
|||||||
+78
-31
@@ -100,7 +100,7 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
AutomaticStackSize: config.AutomaticStackSize(),
|
AutomaticStackSize: config.AutomaticStackSize(),
|
||||||
DefaultStackSize: config.Target.DefaultStackSize,
|
DefaultStackSize: config.Target.DefaultStackSize,
|
||||||
NeedsStackObjects: config.NeedsStackObjects(),
|
NeedsStackObjects: config.NeedsStackObjects(),
|
||||||
Debug: config.Debug(),
|
Debug: true,
|
||||||
LLVMFeatures: config.LLVMFeatures(),
|
LLVMFeatures: config.LLVMFeatures(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,33 +470,10 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
linkerDependencies = append(linkerDependencies, job)
|
linkerDependencies = append(linkerDependencies, job)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add libc dependency if needed.
|
|
||||||
root := goenv.Get("TINYGOROOT")
|
|
||||||
switch config.Target.Libc {
|
|
||||||
case "picolibc":
|
|
||||||
job, err := Picolibc.load(config.Triple(), config.CPU(), dir)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// The library needs to be compiled (cache miss).
|
|
||||||
jobs = append(jobs, job.dependencies...)
|
|
||||||
jobs = append(jobs, job)
|
|
||||||
linkerDependencies = append(linkerDependencies, job)
|
|
||||||
case "wasi-libc":
|
|
||||||
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
|
|
||||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
|
||||||
return errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
|
|
||||||
}
|
|
||||||
ldflags = append(ldflags, path)
|
|
||||||
case "":
|
|
||||||
// no library specified, so nothing to do
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown libc: %s", config.Target.Libc)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add jobs to compile extra files. These files are in C or assembly and
|
// Add jobs to compile extra files. These files are in C or assembly and
|
||||||
// contain things like the interrupt vector table and low level operations
|
// contain things like the interrupt vector table and low level operations
|
||||||
// such as stack switching.
|
// such as stack switching.
|
||||||
|
root := goenv.Get("TINYGOROOT")
|
||||||
for _, path := range config.ExtraFiles() {
|
for _, path := range config.ExtraFiles() {
|
||||||
abspath := filepath.Join(root, path)
|
abspath := filepath.Join(root, path)
|
||||||
job := &compileJob{
|
job := &compileJob{
|
||||||
@@ -537,6 +514,64 @@ func Build(pkgName, outpath string, config *compileopts.Config, action func(Buil
|
|||||||
ldflags = append(ldflags, lprogram.LDFlags...)
|
ldflags = append(ldflags, lprogram.LDFlags...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add libc dependency if needed.
|
||||||
|
switch config.Target.Libc {
|
||||||
|
case "picolibc":
|
||||||
|
job, err := Picolibc.load(config.Triple(), config.CPU(), dir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// The library needs to be compiled (cache miss).
|
||||||
|
jobs = append(jobs, job.dependencies...)
|
||||||
|
jobs = append(jobs, job)
|
||||||
|
linkerDependencies = append(linkerDependencies, job)
|
||||||
|
case "wasi-libc":
|
||||||
|
path := filepath.Join(root, "lib/wasi-libc/sysroot/lib/wasm32-wasi/libc.a")
|
||||||
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
|
return errors.New("could not find wasi-libc, perhaps you need to run `make wasi-libc`?")
|
||||||
|
}
|
||||||
|
job := dummyCompileJob(path)
|
||||||
|
jobs = append(jobs, job)
|
||||||
|
linkerDependencies = append(linkerDependencies, job)
|
||||||
|
case "":
|
||||||
|
// no library specified, so nothing to do
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown libc: %s", config.Target.Libc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Strip debug information with -no-debug.
|
||||||
|
if !config.Debug() {
|
||||||
|
for _, tag := range config.BuildTags() {
|
||||||
|
if tag == "baremetal" {
|
||||||
|
// Don't use -no-debug on baremetal targets. It makes no sense:
|
||||||
|
// the debug information isn't flashed to the device anyway.
|
||||||
|
return fmt.Errorf("stripping debug information is unnecessary for baremetal targets")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if config.Target.Linker == "wasm-ld" {
|
||||||
|
// Don't just strip debug information, also compress relocations
|
||||||
|
// while we're at it. Relocations can only be compressed when debug
|
||||||
|
// information is stripped.
|
||||||
|
ldflags = append(ldflags, "--strip-debug", "--compress-relocations")
|
||||||
|
} else {
|
||||||
|
switch config.GOOS() {
|
||||||
|
case "linux":
|
||||||
|
// Either real linux or an embedded system (like AVR) that
|
||||||
|
// pretends to be Linux. It's a ELF linker wrapped by GCC in any
|
||||||
|
// case.
|
||||||
|
ldflags = append(ldflags, "-Wl,--strip-debug")
|
||||||
|
case "darwin":
|
||||||
|
// MacOS (darwin) doesn't have a linker flag to strip debug
|
||||||
|
// information. Apple expects you to use the strip command
|
||||||
|
// instead.
|
||||||
|
return errors.New("cannot remove debug information: MacOS doesn't suppor this linker flag")
|
||||||
|
default:
|
||||||
|
// Other OSes may have different flags.
|
||||||
|
return errors.New("cannot remove debug information: unknown OS: " + config.GOOS())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Create a linker job, which links all object files together and does some
|
// Create a linker job, which links all object files together and does some
|
||||||
// extra stuff that can only be done after linking.
|
// extra stuff that can only be done after linking.
|
||||||
jobs = append(jobs, &compileJob{
|
jobs = append(jobs, &compileJob{
|
||||||
@@ -953,15 +988,19 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map
|
|||||||
if fn.stackSizeType == stacksize.Bounded {
|
if fn.stackSizeType == stacksize.Bounded {
|
||||||
stackSize := uint32(fn.stackSize)
|
stackSize := uint32(fn.stackSize)
|
||||||
|
|
||||||
// Adding 4 for the stack canary. Even though the size may be
|
|
||||||
// automatically determined, stack overflow checking is still
|
|
||||||
// important as the stack size cannot be determined for all
|
|
||||||
// goroutines.
|
|
||||||
stackSize += 4
|
|
||||||
|
|
||||||
// Add stack size used by interrupts.
|
// Add stack size used by interrupts.
|
||||||
switch fileHeader.Machine {
|
switch fileHeader.Machine {
|
||||||
case elf.EM_ARM:
|
case elf.EM_ARM:
|
||||||
|
if stackSize%8 != 0 {
|
||||||
|
// If the stack isn't a multiple of 8, it means the leaf
|
||||||
|
// function with the biggest stack depth doesn't have an aligned
|
||||||
|
// stack. If the STKALIGN flag is set (which it is by default)
|
||||||
|
// the interrupt controller will forcibly align the stack before
|
||||||
|
// storing in-use registers. This will thus overwrite one word
|
||||||
|
// past the end of the stack (off-by-one).
|
||||||
|
stackSize += 4
|
||||||
|
}
|
||||||
|
|
||||||
// On Cortex-M (assumed here), this stack size is 8 words or 32
|
// On Cortex-M (assumed here), this stack size is 8 words or 32
|
||||||
// bytes. This is only to store the registers that the interrupt
|
// bytes. This is only to store the registers that the interrupt
|
||||||
// may modify, the interrupt will switch to the interrupt stack
|
// may modify, the interrupt will switch to the interrupt stack
|
||||||
@@ -969,6 +1008,14 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map
|
|||||||
// Some background:
|
// Some background:
|
||||||
// https://interrupt.memfault.com/blog/cortex-m-rtos-context-switching
|
// https://interrupt.memfault.com/blog/cortex-m-rtos-context-switching
|
||||||
stackSize += 32
|
stackSize += 32
|
||||||
|
|
||||||
|
// Adding 4 for the stack canary, and another 4 to keep the
|
||||||
|
// stack aligned. Even though the size may be automatically
|
||||||
|
// determined, stack overflow checking is still important as the
|
||||||
|
// stack size cannot be determined for all goroutines.
|
||||||
|
stackSize += 8
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown architecture: %s", fileHeader.Machine.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally write the stack size to the binary.
|
// Finally write the stack size to the binary.
|
||||||
|
|||||||
+18
-6
@@ -55,7 +55,7 @@ func (c *Config) GOARCH() string {
|
|||||||
|
|
||||||
// BuildTags returns the complete list of build tags used during this build.
|
// BuildTags returns the complete list of build tags used during this build.
|
||||||
func (c *Config) BuildTags() []string {
|
func (c *Config) BuildTags() []string {
|
||||||
tags := append(c.Target.BuildTags, []string{"tinygo", "gc." + c.GC(), "scheduler." + c.Scheduler()}...)
|
tags := append(c.Target.BuildTags, []string{"tinygo", "math_big_pure_go", "gc." + c.GC(), "scheduler." + c.Scheduler(), "serial." + c.Serial()}...)
|
||||||
for i := 1; i <= c.GoMinorVersion; i++ {
|
for i := 1; i <= c.GoMinorVersion; i++ {
|
||||||
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
tags = append(tags, fmt.Sprintf("go1.%d", i))
|
||||||
}
|
}
|
||||||
@@ -113,6 +113,18 @@ func (c *Config) Scheduler() string {
|
|||||||
return "coroutines"
|
return "coroutines"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serial returns the serial implementation for this build configuration: uart,
|
||||||
|
// usb (meaning USB-CDC), or none.
|
||||||
|
func (c *Config) Serial() string {
|
||||||
|
if c.Options.Serial != "" {
|
||||||
|
return c.Options.Serial
|
||||||
|
}
|
||||||
|
if c.Target.Serial != "" {
|
||||||
|
return c.Target.Serial
|
||||||
|
}
|
||||||
|
return "none"
|
||||||
|
}
|
||||||
|
|
||||||
// OptLevels returns the optimization level (0-2), size level (0-2), and inliner
|
// OptLevels returns the optimization level (0-2), size level (0-2), and inliner
|
||||||
// threshold as used in the LLVM optimization pipeline.
|
// threshold as used in the LLVM optimization pipeline.
|
||||||
func (c *Config) OptLevels() (optLevel, sizeLevel int, inlinerThreshold uint) {
|
func (c *Config) OptLevels() (optLevel, sizeLevel int, inlinerThreshold uint) {
|
||||||
@@ -197,9 +209,8 @@ func (c *Config) CFlags() []string {
|
|||||||
cflags = append(cflags, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include"))
|
cflags = append(cflags, "-nostdlibinc", "-Xclang", "-internal-isystem", "-Xclang", filepath.Join(root, "lib", "picolibc", "newlib", "libc", "include"))
|
||||||
cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include"))
|
cflags = append(cflags, "-I"+filepath.Join(root, "lib/picolibc-include"))
|
||||||
}
|
}
|
||||||
if c.Debug() {
|
// Always emit debug information. It is optionally stripped at link time.
|
||||||
cflags = append(cflags, "-g")
|
cflags = append(cflags, "-g")
|
||||||
}
|
|
||||||
return cflags
|
return cflags
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,8 +249,9 @@ func (c *Config) VerifyIR() bool {
|
|||||||
return c.Options.VerifyIR
|
return c.Options.VerifyIR
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug returns whether to add debug symbols to the IR, for debugging with GDB
|
// Debug returns whether debug (DWARF) information should be retained by the
|
||||||
// and similar.
|
// linker. By default, debug information is retained but it can be removed with
|
||||||
|
// the -no-debug flag.
|
||||||
func (c *Config) Debug() bool {
|
func (c *Config) Debug() bool {
|
||||||
return c.Options.Debug
|
return c.Options.Debug
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
validGCOptions = []string{"none", "leaking", "extalloc", "conservative"}
|
validGCOptions = []string{"none", "leaking", "extalloc", "conservative"}
|
||||||
validSchedulerOptions = []string{"none", "tasks", "coroutines"}
|
validSchedulerOptions = []string{"none", "tasks", "coroutines"}
|
||||||
|
validSerialOptions = []string{"none", "uart", "usb"}
|
||||||
validPrintSizeOptions = []string{"none", "short", "full"}
|
validPrintSizeOptions = []string{"none", "short", "full"}
|
||||||
validPanicStrategyOptions = []string{"print", "trap"}
|
validPanicStrategyOptions = []string{"print", "trap"}
|
||||||
validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
|
validOptOptions = []string{"none", "0", "1", "2", "s", "z"}
|
||||||
@@ -22,6 +23,7 @@ type Options struct {
|
|||||||
GC string
|
GC string
|
||||||
PanicStrategy string
|
PanicStrategy string
|
||||||
Scheduler string
|
Scheduler string
|
||||||
|
Serial string
|
||||||
PrintIR bool
|
PrintIR bool
|
||||||
DumpSSA bool
|
DumpSSA bool
|
||||||
VerifyIR bool
|
VerifyIR bool
|
||||||
@@ -59,6 +61,15 @@ func (o *Options) Verify() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if o.Serial != "" {
|
||||||
|
valid := isInArray(validSerialOptions, o.Serial)
|
||||||
|
if !valid {
|
||||||
|
return fmt.Errorf(`invalid serial option '%s': valid values are %s`,
|
||||||
|
o.Serial,
|
||||||
|
strings.Join(validSerialOptions, ", "))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if o.PrintSizes != "" {
|
if o.PrintSizes != "" {
|
||||||
valid := isInArray(validPrintSizeOptions, o.PrintSizes)
|
valid := isInArray(validPrintSizeOptions, o.PrintSizes)
|
||||||
if !valid {
|
if !valid {
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ type TargetSpec struct {
|
|||||||
BuildTags []string `json:"build-tags"`
|
BuildTags []string `json:"build-tags"`
|
||||||
GC string `json:"gc"`
|
GC string `json:"gc"`
|
||||||
Scheduler string `json:"scheduler"`
|
Scheduler string `json:"scheduler"`
|
||||||
|
Serial string `json:"serial"` // which serial output to use (uart, usb, none)
|
||||||
Linker string `json:"linker"`
|
Linker string `json:"linker"`
|
||||||
RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt)
|
RTLib string `json:"rtlib"` // compiler runtime library (libgcc, compiler-rt)
|
||||||
Libc string `json:"libc"`
|
Libc string `json:"libc"`
|
||||||
|
|||||||
+12
-4
@@ -23,7 +23,7 @@ import (
|
|||||||
// Version of the compiler pacakge. Must be incremented each time the compiler
|
// Version of the compiler pacakge. Must be incremented each time the compiler
|
||||||
// package changes in a way that affects the generated LLVM module.
|
// package changes in a way that affects the generated LLVM module.
|
||||||
// This version is independent of the TinyGo version number.
|
// This version is independent of the TinyGo version number.
|
||||||
const Version = 11 // last change: change method name globals
|
const Version = 12 // last change: implement syscall.rawSyscallNoError
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
llvm.InitializeAllTargets()
|
llvm.InitializeAllTargets()
|
||||||
@@ -715,11 +715,11 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
|||||||
member := pkg.Members[name]
|
member := pkg.Members[name]
|
||||||
switch member := member.(type) {
|
switch member := member.(type) {
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
|
// Create the function definition.
|
||||||
|
b := newBuilder(c, irbuilder, member)
|
||||||
if member.Blocks == nil {
|
if member.Blocks == nil {
|
||||||
continue // external function
|
continue // external function
|
||||||
}
|
}
|
||||||
// Create the function definition.
|
|
||||||
b := newBuilder(c, irbuilder, member)
|
|
||||||
b.createFunction()
|
b.createFunction()
|
||||||
case *ssa.Type:
|
case *ssa.Type:
|
||||||
if types.IsInterface(member.Type()) {
|
if types.IsInterface(member.Type()) {
|
||||||
@@ -758,10 +758,13 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
|||||||
case *ssa.Global:
|
case *ssa.Global:
|
||||||
// Global variable.
|
// Global variable.
|
||||||
info := c.getGlobalInfo(member)
|
info := c.getGlobalInfo(member)
|
||||||
|
global := c.getGlobal(member)
|
||||||
if !info.extern {
|
if !info.extern {
|
||||||
global := c.getGlobal(member)
|
|
||||||
global.SetInitializer(llvm.ConstNull(global.Type().ElementType()))
|
global.SetInitializer(llvm.ConstNull(global.Type().ElementType()))
|
||||||
global.SetVisibility(llvm.HiddenVisibility)
|
global.SetVisibility(llvm.HiddenVisibility)
|
||||||
|
if info.section != "" {
|
||||||
|
global.SetSection(info.section)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -787,6 +790,9 @@ func (b *builder) createFunction() {
|
|||||||
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
||||||
b.llvmFn.SetUnnamedAddr(true)
|
b.llvmFn.SetUnnamedAddr(true)
|
||||||
}
|
}
|
||||||
|
if b.info.section != "" {
|
||||||
|
b.llvmFn.SetSection(b.info.section)
|
||||||
|
}
|
||||||
if b.info.exported && strings.HasPrefix(b.Triple, "wasm") {
|
if b.info.exported && strings.HasPrefix(b.Triple, "wasm") {
|
||||||
// Set the exported name. This is necessary for WebAssembly because
|
// Set the exported name. This is necessary for WebAssembly because
|
||||||
// otherwise the function is not exported.
|
// otherwise the function is not exported.
|
||||||
@@ -1304,6 +1310,8 @@ func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error)
|
|||||||
return b.emitCSROperation(instr)
|
return b.emitCSROperation(instr)
|
||||||
case strings.HasPrefix(name, "syscall.Syscall"):
|
case strings.HasPrefix(name, "syscall.Syscall"):
|
||||||
return b.createSyscall(instr)
|
return b.createSyscall(instr)
|
||||||
|
case strings.HasPrefix(name, "syscall.rawSyscallNoError"):
|
||||||
|
return b.createRawSyscallNoError(instr)
|
||||||
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
case strings.HasPrefix(name, "runtime/volatile.Load"):
|
||||||
return b.createVolatileLoad(instr)
|
return b.createVolatileLoad(instr)
|
||||||
case strings.HasPrefix(name, "runtime/volatile.Store"):
|
case strings.HasPrefix(name, "runtime/volatile.Store"):
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ func TestCompiler(t *testing.T) {
|
|||||||
{"float.go", ""},
|
{"float.go", ""},
|
||||||
{"interface.go", ""},
|
{"interface.go", ""},
|
||||||
{"func.go", ""},
|
{"func.go", ""},
|
||||||
|
{"pragma.go", ""},
|
||||||
{"goroutine.go", "wasm"},
|
{"goroutine.go", "wasm"},
|
||||||
{"goroutine.go", "cortex-m-qemu"},
|
{"goroutine.go", "cortex-m-qemu"},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ type functionInfo struct {
|
|||||||
module string // go:wasm-module
|
module string // go:wasm-module
|
||||||
importName string // go:linkname, go:export - The name the developer assigns
|
importName string // go:linkname, go:export - The name the developer assigns
|
||||||
linkName string // go:linkname, go:export - The name that we map for the particular module -> importName
|
linkName string // go:linkname, go:export - The name that we map for the particular module -> importName
|
||||||
|
section string // go:section - object file section name
|
||||||
exported bool // go:export, CGo
|
exported bool // go:export, CGo
|
||||||
nobounds bool // go:nobounds
|
nobounds bool // go:nobounds
|
||||||
variadic bool // go:variadic (CGo only)
|
variadic bool // go:variadic (CGo only)
|
||||||
@@ -270,6 +271,10 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
|
|||||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||||
info.linkName = parts[2]
|
info.linkName = parts[2]
|
||||||
}
|
}
|
||||||
|
case "//go:section":
|
||||||
|
if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) {
|
||||||
|
info.section = parts[1]
|
||||||
|
}
|
||||||
case "//go:nobounds":
|
case "//go:nobounds":
|
||||||
// Skip bounds checking in this function. Useful for some
|
// Skip bounds checking in this function. Useful for some
|
||||||
// runtime functions.
|
// runtime functions.
|
||||||
@@ -325,6 +330,7 @@ type globalInfo struct {
|
|||||||
linkName string // go:extern
|
linkName string // go:extern
|
||||||
extern bool // go:extern
|
extern bool // go:extern
|
||||||
align int // go:align
|
align int // go:align
|
||||||
|
section string // go:section
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadASTComments loads comments on globals from the AST, for use later in the
|
// loadASTComments loads comments on globals from the AST, for use later in the
|
||||||
@@ -438,6 +444,10 @@ func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
info.align = align
|
info.align = align
|
||||||
}
|
}
|
||||||
|
case "//go:section":
|
||||||
|
if len(parts) == 2 {
|
||||||
|
info.section = parts[1]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-8
@@ -10,11 +10,11 @@ import (
|
|||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// createSyscall emits an inline system call instruction, depending on the
|
// createRawSyscall creates a system call with the provided system call number
|
||||||
// target OS/arch.
|
// and returns the result as a single integer (the system call result). The
|
||||||
func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
// result is not further interpreted.
|
||||||
|
func (b *builder) createRawSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||||
num := b.getValue(call.Args[0])
|
num := b.getValue(call.Args[0])
|
||||||
var syscallResult llvm.Value
|
|
||||||
switch {
|
switch {
|
||||||
case b.GOARCH == "amd64":
|
case b.GOARCH == "amd64":
|
||||||
if b.GOOS == "darwin" {
|
if b.GOOS == "darwin" {
|
||||||
@@ -57,7 +57,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
constraints += ",~{rcx},~{r11}"
|
constraints += ",~{rcx},~{r11}"
|
||||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||||
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel)
|
target := llvm.InlineAsm(fnType, "syscall", constraints, true, false, llvm.InlineAsmDialectIntel)
|
||||||
syscallResult = b.CreateCall(target, args, "")
|
return b.CreateCall(target, args, ""), nil
|
||||||
case b.GOARCH == "386" && b.GOOS == "linux":
|
case b.GOARCH == "386" && b.GOOS == "linux":
|
||||||
// Sources:
|
// Sources:
|
||||||
// syscall(2) man page
|
// syscall(2) man page
|
||||||
@@ -83,7 +83,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
}
|
}
|
||||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||||
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel)
|
target := llvm.InlineAsm(fnType, "int 0x80", constraints, true, false, llvm.InlineAsmDialectIntel)
|
||||||
syscallResult = b.CreateCall(target, args, "")
|
return b.CreateCall(target, args, ""), nil
|
||||||
case b.GOARCH == "arm" && b.GOOS == "linux":
|
case b.GOARCH == "arm" && b.GOOS == "linux":
|
||||||
// Implement the EABI system call convention for Linux.
|
// Implement the EABI system call convention for Linux.
|
||||||
// Source: syscall(2) man page.
|
// Source: syscall(2) man page.
|
||||||
@@ -115,7 +115,7 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
}
|
}
|
||||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
|
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
|
||||||
syscallResult = b.CreateCall(target, args, "")
|
return b.CreateCall(target, args, ""), nil
|
||||||
case b.GOARCH == "arm64" && b.GOOS == "linux":
|
case b.GOARCH == "arm64" && b.GOOS == "linux":
|
||||||
// Source: syscall(2) man page.
|
// Source: syscall(2) man page.
|
||||||
args := []llvm.Value{}
|
args := []llvm.Value{}
|
||||||
@@ -147,10 +147,19 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
constraints += ",~{x16},~{x17}" // scratch registers
|
constraints += ",~{x16},~{x17}" // scratch registers
|
||||||
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
fnType := llvm.FunctionType(b.uintptrType, argTypes, false)
|
||||||
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
|
target := llvm.InlineAsm(fnType, "svc #0", constraints, true, false, 0)
|
||||||
syscallResult = b.CreateCall(target, args, "")
|
return b.CreateCall(target, args, ""), nil
|
||||||
default:
|
default:
|
||||||
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
|
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// createSyscall emits instructions for the syscall.Syscall* family of
|
||||||
|
// functions, depending on the target OS/arch.
|
||||||
|
func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
||||||
|
syscallResult, err := b.createRawSyscall(call)
|
||||||
|
if err != nil {
|
||||||
|
return syscallResult, err
|
||||||
|
}
|
||||||
switch b.GOOS {
|
switch b.GOOS {
|
||||||
case "linux", "freebsd":
|
case "linux", "freebsd":
|
||||||
// Return values: r0, r1 uintptr, err Errno
|
// Return values: r0, r1 uintptr, err Errno
|
||||||
@@ -190,3 +199,16 @@ func (b *builder) createSyscall(call *ssa.CallCommon) (llvm.Value, error) {
|
|||||||
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
|
return llvm.Value{}, b.makeError(call.Pos(), "unknown GOOS/GOARCH for syscall: "+b.GOOS+"/"+b.GOARCH)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createRawSyscallNoError emits instructions for the Linux-specific
|
||||||
|
// syscall.rawSyscallNoError function.
|
||||||
|
func (b *builder) createRawSyscallNoError(call *ssa.CallCommon) (llvm.Value, error) {
|
||||||
|
syscallResult, err := b.createRawSyscall(call)
|
||||||
|
if err != nil {
|
||||||
|
return syscallResult, err
|
||||||
|
}
|
||||||
|
retval := llvm.ConstNull(b.ctx.StructType([]llvm.Type{b.uintptrType, b.uintptrType}, false))
|
||||||
|
retval = b.CreateInsertValue(retval, syscallResult, 0, "")
|
||||||
|
retval = b.CreateInsertValue(retval, llvm.ConstInt(b.uintptrType, 0, false), 1, "")
|
||||||
|
return retval, nil
|
||||||
|
}
|
||||||
|
|||||||
Vendored
+66
@@ -0,0 +1,66 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import _ "unsafe"
|
||||||
|
|
||||||
|
// Creates an external global with name extern_global.
|
||||||
|
//go:extern extern_global
|
||||||
|
var externGlobal [0]byte
|
||||||
|
|
||||||
|
// Creates a
|
||||||
|
//go:align 32
|
||||||
|
var alignedGlobal [4]uint32
|
||||||
|
|
||||||
|
// Test conflicting pragmas (the last one counts).
|
||||||
|
//go:align 64
|
||||||
|
//go:align 16
|
||||||
|
var alignedGlobal16 [4]uint32
|
||||||
|
|
||||||
|
// Test exported functions.
|
||||||
|
//export extern_func
|
||||||
|
func externFunc() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define a function in a different package using go:linkname.
|
||||||
|
//go:linkname withLinkageName1 somepkg.someFunction1
|
||||||
|
func withLinkageName1() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import a function from a different package using go:linkname.
|
||||||
|
//go:linkname withLinkageName2 somepkg.someFunction2
|
||||||
|
func withLinkageName2()
|
||||||
|
|
||||||
|
// Function has an 'inline hint', similar to the inline keyword in C.
|
||||||
|
//go:inline
|
||||||
|
func inlineFunc() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function should never be inlined, equivalent to GCC
|
||||||
|
// __attribute__((noinline)).
|
||||||
|
//go:noinline
|
||||||
|
func noinlineFunc() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function should have the specified section.
|
||||||
|
//go:section .special_function_section
|
||||||
|
func functionInSection() {
|
||||||
|
}
|
||||||
|
|
||||||
|
//export exportedFunctionInSection
|
||||||
|
//go:section .special_function_section
|
||||||
|
func exportedFunctionInSection() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function should not: it's only a declaration and not a definition.
|
||||||
|
//go:section .special_function_section
|
||||||
|
func undefinedFunctionNotInSection()
|
||||||
|
|
||||||
|
//go:section .special_global_section
|
||||||
|
var globalInSection uint32
|
||||||
|
|
||||||
|
//go:section .special_global_section
|
||||||
|
//go:extern undefinedGlobalNotInSection
|
||||||
|
var undefinedGlobalNotInSection uint32
|
||||||
|
|
||||||
|
//go:align 1024
|
||||||
|
//go:section .global_section
|
||||||
|
var multipleGlobalPragmas uint32
|
||||||
Vendored
+59
@@ -0,0 +1,59 @@
|
|||||||
|
; ModuleID = 'pragma.go'
|
||||||
|
source_filename = "pragma.go"
|
||||||
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
||||||
|
target triple = "wasm32--wasi"
|
||||||
|
|
||||||
|
@extern_global = external global [0 x i8], align 1
|
||||||
|
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
|
||||||
|
@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16
|
||||||
|
@main.globalInSection = hidden global i32 0, section ".special_global_section", align 4
|
||||||
|
@undefinedGlobalNotInSection = external global i32, align 4
|
||||||
|
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
|
||||||
|
|
||||||
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
|
define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @extern_func() #0 {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define hidden void @somepkg.someFunction1(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @somepkg.someFunction2(i8*, i8*)
|
||||||
|
|
||||||
|
; Function Attrs: inlinehint
|
||||||
|
define hidden void @main.inlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #1 {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; Function Attrs: noinline
|
||||||
|
define hidden void @main.noinlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #2 {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define hidden void @main.functionInSection(i8* %context, i8* %parentHandle) unnamed_addr section ".special_function_section" {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @exportedFunctionInSection() #3 section ".special_function_section" {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @main.undefinedFunctionNotInSection(i8*, i8*)
|
||||||
|
|
||||||
|
attributes #0 = { "wasm-export-name"="extern_func" }
|
||||||
|
attributes #1 = { inlinehint }
|
||||||
|
attributes #2 = { noinline }
|
||||||
|
attributes #3 = { "wasm-export-name"="exportedFunctionInSection" }
|
||||||
+1
-1
@@ -12,7 +12,7 @@ import (
|
|||||||
|
|
||||||
// Version of TinyGo.
|
// Version of TinyGo.
|
||||||
// Update this value before release of new version of software.
|
// Update this value before release of new version of software.
|
||||||
const Version = "0.19.0-dev"
|
const Version = "0.20.0-dev"
|
||||||
|
|
||||||
// GetGorootVersion returns the major and minor version for a given GOROOT path.
|
// GetGorootVersion returns the major and minor version for a given GOROOT path.
|
||||||
// If the goroot cannot be determined, (0, 0) is returned.
|
// If the goroot cannot be determined, (0, 0) is returned.
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ func (r *runner) errorAt(inst instruction, err error) *Error {
|
|||||||
pos := getPosition(inst.llvmInst)
|
pos := getPosition(inst.llvmInst)
|
||||||
return &Error{
|
return &Error{
|
||||||
ImportPath: r.pkgName,
|
ImportPath: r.pkgName,
|
||||||
|
Inst: inst.llvmInst,
|
||||||
Pos: pos,
|
Pos: pos,
|
||||||
Err: err,
|
Err: err,
|
||||||
Traceback: []ErrorLine{{pos, inst.llvmInst}},
|
Traceback: []ErrorLine{{pos, inst.llvmInst}},
|
||||||
|
|||||||
+27
-2
@@ -15,7 +15,7 @@ import (
|
|||||||
// package is changed in a way that affects the output so that cached package
|
// package is changed in a way that affects the output so that cached package
|
||||||
// builds will be invalidated.
|
// builds will be invalidated.
|
||||||
// This version is independent of the TinyGo version number.
|
// This version is independent of the TinyGo version number.
|
||||||
const Version = 1
|
const Version = 2 // last change: fix GEP on untyped pointers
|
||||||
|
|
||||||
// Enable extra checks, which should be disabled by default.
|
// Enable extra checks, which should be disabled by default.
|
||||||
// This may help track down bugs by adding a few more sanity checks.
|
// This may help track down bugs by adding a few more sanity checks.
|
||||||
@@ -110,17 +110,26 @@ func Run(mod llvm.Module, debug bool) error {
|
|||||||
fmt.Fprintln(os.Stderr, "call:", fn.Name())
|
fmt.Fprintln(os.Stderr, "call:", fn.Name())
|
||||||
}
|
}
|
||||||
_, mem, callErr := r.run(r.getFunction(fn), nil, nil, " ")
|
_, mem, callErr := r.run(r.getFunction(fn), nil, nil, " ")
|
||||||
|
call.EraseFromParentAsInstruction()
|
||||||
if callErr != nil {
|
if callErr != nil {
|
||||||
if isRecoverableError(callErr.Err) {
|
if isRecoverableError(callErr.Err) {
|
||||||
if r.debug {
|
if r.debug {
|
||||||
fmt.Fprintln(os.Stderr, "not interpreting", r.pkgName, "because of error:", callErr.Error())
|
fmt.Fprintln(os.Stderr, "not interpreting", r.pkgName, "because of error:", callErr.Error())
|
||||||
}
|
}
|
||||||
|
// Remove instructions that were created as part of interpreting
|
||||||
|
// the package.
|
||||||
mem.revert()
|
mem.revert()
|
||||||
|
// Create a call to the package initializer (which was
|
||||||
|
// previously deleted).
|
||||||
|
i8undef := llvm.Undef(r.i8ptrType)
|
||||||
|
r.builder.CreateCall(fn, []llvm.Value{i8undef, i8undef}, "")
|
||||||
|
// Make sure that any globals touched by the package
|
||||||
|
// initializer, won't be accessed by later package initializers.
|
||||||
|
r.markExternalLoad(fn)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return callErr
|
return callErr
|
||||||
}
|
}
|
||||||
call.EraseFromParentAsInstruction()
|
|
||||||
for index, obj := range mem.objects {
|
for index, obj := range mem.objects {
|
||||||
r.objects[index] = obj
|
r.objects[index] = obj
|
||||||
}
|
}
|
||||||
@@ -270,3 +279,19 @@ func (r *runner) getFunction(llvmFn llvm.Value) *function {
|
|||||||
r.functionCache[llvmFn] = fn
|
r.functionCache[llvmFn] = fn
|
||||||
return fn
|
return fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// markExternalLoad marks the given llvmValue as being loaded externally. This
|
||||||
|
// is primarily used to mark package initializers that could not be run at
|
||||||
|
// compile time. As an example, a package initialize might store to a global
|
||||||
|
// variable. Another package initializer might read from the same global
|
||||||
|
// variable. By marking this function as being run at runtime, that load
|
||||||
|
// instruction will need to be run at runtime instead of at compile time.
|
||||||
|
func (r *runner) markExternalLoad(llvmValue llvm.Value) {
|
||||||
|
mem := memoryView{r: r}
|
||||||
|
mem.markExternalLoad(llvmValue)
|
||||||
|
for index, obj := range mem.objects {
|
||||||
|
if obj.marked > r.objects[index].marked {
|
||||||
|
r.objects[index].marked = obj.marked
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ func TestInterp(t *testing.T) {
|
|||||||
"slice-copy",
|
"slice-copy",
|
||||||
"consteval",
|
"consteval",
|
||||||
"interface",
|
"interface",
|
||||||
|
"revert",
|
||||||
} {
|
} {
|
||||||
name := name // make tc local to this closure
|
name := name // make tc local to this closure
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
|
|||||||
@@ -572,6 +572,17 @@ func (v pointerValue) toLLVMValue(llvmType llvm.Type, mem *memoryView) (llvm.Val
|
|||||||
}
|
}
|
||||||
|
|
||||||
if llvmType.IsNil() {
|
if llvmType.IsNil() {
|
||||||
|
if v.offset() != 0 {
|
||||||
|
// If there is an offset, make sure to use a GEP to index into the
|
||||||
|
// pointer. Because there is no expected type, we use whatever is
|
||||||
|
// most convenient: an *i8 type. It is trivial to index byte-wise.
|
||||||
|
if llvmValue.Type() != mem.r.i8ptrType {
|
||||||
|
llvmValue = llvm.ConstBitCast(llvmValue, mem.r.i8ptrType)
|
||||||
|
}
|
||||||
|
llvmValue = llvm.ConstInBoundsGEP(llvmValue, []llvm.Value{
|
||||||
|
llvm.ConstInt(llvmValue.Type().Context().Int32Type(), uint64(v.offset()), false),
|
||||||
|
})
|
||||||
|
}
|
||||||
return llvmValue, nil
|
return llvmValue, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+32
@@ -0,0 +1,32 @@
|
|||||||
|
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||||
|
target triple = "x86_64--linux"
|
||||||
|
|
||||||
|
declare void @externalCall(i64)
|
||||||
|
|
||||||
|
@foo.knownAtRuntime = global i64 0
|
||||||
|
@bar.knownAtRuntime = global i64 0
|
||||||
|
|
||||||
|
define void @runtime.initAll() unnamed_addr {
|
||||||
|
entry:
|
||||||
|
call void @foo.init(i8* undef, i8* undef)
|
||||||
|
call void @bar.init(i8* undef, i8* undef)
|
||||||
|
call void @main.init(i8* undef, i8* undef)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal void @foo.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||||
|
store i64 5, i64* @foo.knownAtRuntime
|
||||||
|
unreachable ; this triggers a revert of @foo.init.
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal void @bar.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||||
|
%val = load i64, i64* @foo.knownAtRuntime
|
||||||
|
store i64 %val, i64* @bar.knownAtRuntime
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal void @main.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||||
|
entry:
|
||||||
|
call void @externalCall(i64 3)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||||
|
target triple = "x86_64--linux"
|
||||||
|
|
||||||
|
@foo.knownAtRuntime = local_unnamed_addr global i64 0
|
||||||
|
@bar.knownAtRuntime = local_unnamed_addr global i64 0
|
||||||
|
|
||||||
|
declare void @externalCall(i64) local_unnamed_addr
|
||||||
|
|
||||||
|
define void @runtime.initAll() unnamed_addr {
|
||||||
|
entry:
|
||||||
|
call fastcc void @foo.init(i8* undef, i8* undef)
|
||||||
|
%val = load i64, i64* @foo.knownAtRuntime, align 8
|
||||||
|
store i64 %val, i64* @bar.knownAtRuntime, align 8
|
||||||
|
call void @externalCall(i64 3)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define internal fastcc void @foo.init(i8* %context, i8* %parentHandle) unnamed_addr {
|
||||||
|
store i64 5, i64* @foo.knownAtRuntime, align 8
|
||||||
|
unreachable
|
||||||
|
}
|
||||||
@@ -1009,6 +1009,7 @@ func main() {
|
|||||||
gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, conservative)")
|
gc := flag.String("gc", "", "garbage collector to use (none, leaking, extalloc, conservative)")
|
||||||
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
|
panicStrategy := flag.String("panic", "print", "panic strategy (print, trap)")
|
||||||
scheduler := flag.String("scheduler", "", "which scheduler to use (none, coroutines, tasks)")
|
scheduler := flag.String("scheduler", "", "which scheduler to use (none, coroutines, tasks)")
|
||||||
|
serial := flag.String("serial", "", "which serial output to use (none, uart, usb)")
|
||||||
printIR := flag.Bool("printir", false, "print LLVM IR")
|
printIR := flag.Bool("printir", false, "print LLVM IR")
|
||||||
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
|
dumpSSA := flag.Bool("dumpssa", false, "dump internal Go SSA")
|
||||||
verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR")
|
verifyIR := flag.Bool("verifyir", false, "run extra verification steps on LLVM IR")
|
||||||
@@ -1018,7 +1019,7 @@ func main() {
|
|||||||
printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines")
|
printStacks := flag.Bool("print-stacks", false, "print stack sizes of goroutines")
|
||||||
printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
|
printAllocsString := flag.String("print-allocs", "", "regular expression of functions for which heap allocations should be printed")
|
||||||
printCommands := flag.Bool("x", false, "Print commands")
|
printCommands := flag.Bool("x", false, "Print commands")
|
||||||
nodebug := flag.Bool("no-debug", false, "disable DWARF debug symbol generation")
|
nodebug := flag.Bool("no-debug", false, "strip debug information")
|
||||||
ocdCommandsString := flag.String("ocd-commands", "", "OpenOCD commands, overriding target spec (can specify multiple separated by commas)")
|
ocdCommandsString := flag.String("ocd-commands", "", "OpenOCD commands, overriding target spec (can specify multiple separated by commas)")
|
||||||
ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug")
|
ocdOutput := flag.Bool("ocd-output", false, "print OCD daemon output during debug")
|
||||||
port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)")
|
port := flag.String("port", "", "flash port (can specify multiple candidates separated by commas)")
|
||||||
@@ -1081,6 +1082,7 @@ func main() {
|
|||||||
GC: *gc,
|
GC: *gc,
|
||||||
PanicStrategy: *panicStrategy,
|
PanicStrategy: *panicStrategy,
|
||||||
Scheduler: *scheduler,
|
Scheduler: *scheduler,
|
||||||
|
Serial: *serial,
|
||||||
PrintIR: *printIR,
|
PrintIR: *printIR,
|
||||||
DumpSSA: *dumpSSA,
|
DumpSSA: *dumpSSA,
|
||||||
VerifyIR: *verifyIR,
|
VerifyIR: *verifyIR,
|
||||||
|
|||||||
+14
-15
@@ -125,7 +125,7 @@ func TestCompiler(t *testing.T) {
|
|||||||
// Test with few optimizations enabled (no inlining, etc).
|
// Test with few optimizations enabled (no inlining, etc).
|
||||||
t.Run("opt=1", func(t *testing.T) {
|
t.Run("opt=1", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
runTestWithConfig("stdlib.go", "", t, &compileopts.Options{
|
runTestWithConfig("stdlib.go", "", t, compileopts.Options{
|
||||||
Opt: "1",
|
Opt: "1",
|
||||||
}, nil, nil)
|
}, nil, nil)
|
||||||
})
|
})
|
||||||
@@ -134,15 +134,14 @@ func TestCompiler(t *testing.T) {
|
|||||||
// TODO: fix this for stdlib.go, which currently fails.
|
// TODO: fix this for stdlib.go, which currently fails.
|
||||||
t.Run("opt=0", func(t *testing.T) {
|
t.Run("opt=0", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
runTestWithConfig("print.go", "", t, &compileopts.Options{
|
runTestWithConfig("print.go", "", t, compileopts.Options{
|
||||||
Opt: "0",
|
Opt: "0",
|
||||||
}, nil, nil)
|
}, nil, nil)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ldflags", func(t *testing.T) {
|
t.Run("ldflags", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
runTestWithConfig("ldflags.go", "", t, &compileopts.Options{
|
runTestWithConfig("ldflags.go", "", t, compileopts.Options{
|
||||||
Opt: "z",
|
|
||||||
GlobalValues: map[string]map[string]string{
|
GlobalValues: map[string]map[string]string{
|
||||||
"main": {
|
"main": {
|
||||||
"someGlobal": "foobar",
|
"someGlobal": "foobar",
|
||||||
@@ -188,20 +187,20 @@ func runBuild(src, out string, opts *compileopts.Options) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func runTest(name, target string, t *testing.T, cmdArgs, environmentVars []string) {
|
func runTest(name, target string, t *testing.T, cmdArgs, environmentVars []string) {
|
||||||
options := &compileopts.Options{
|
options := compileopts.Options{
|
||||||
Target: target,
|
Target: target,
|
||||||
Opt: "z",
|
|
||||||
PrintIR: false,
|
|
||||||
DumpSSA: false,
|
|
||||||
VerifyIR: true,
|
|
||||||
Debug: true,
|
|
||||||
PrintSizes: "",
|
|
||||||
WasmAbi: "",
|
|
||||||
}
|
}
|
||||||
runTestWithConfig(name, target, t, options, cmdArgs, environmentVars)
|
runTestWithConfig(name, target, t, options, cmdArgs, environmentVars)
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTestWithConfig(name, target string, t *testing.T, options *compileopts.Options, cmdArgs, environmentVars []string) {
|
func runTestWithConfig(name, target string, t *testing.T, options compileopts.Options, cmdArgs, environmentVars []string) {
|
||||||
|
// Set default config.
|
||||||
|
options.Debug = true
|
||||||
|
options.VerifyIR = true
|
||||||
|
if options.Opt == "" {
|
||||||
|
options.Opt = "z"
|
||||||
|
}
|
||||||
|
|
||||||
// Get the expected output for this test.
|
// Get the expected output for this test.
|
||||||
// Note: not using filepath.Join as it strips the path separator at the end
|
// Note: not using filepath.Join as it strips the path separator at the end
|
||||||
// of the path.
|
// of the path.
|
||||||
@@ -230,7 +229,7 @@ func runTestWithConfig(name, target string, t *testing.T, options *compileopts.O
|
|||||||
|
|
||||||
// Build the test binary.
|
// Build the test binary.
|
||||||
binary := filepath.Join(tmpdir, "test")
|
binary := filepath.Join(tmpdir, "test")
|
||||||
err = runBuild("./"+path, binary, options)
|
err = runBuild("./"+path, binary, &options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
printCompilerError(t.Log, err)
|
printCompilerError(t.Log, err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
|||||||
@@ -47,8 +47,6 @@ const (
|
|||||||
LED = D6
|
LED = D6
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// USBCDC pins
|
// USBCDC pins
|
||||||
const (
|
const (
|
||||||
USBCDC_DM_PIN Pin = PA24
|
USBCDC_DM_PIN Pin = PA24
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ const (
|
|||||||
LED3 Pin = PB03 // RX LED
|
LED3 Pin = PB03 // RX LED
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// ADC pins
|
// ADC pins
|
||||||
const (
|
const (
|
||||||
AREF Pin = PA03
|
AREF Pin = PA03
|
||||||
|
|||||||
@@ -74,5 +74,3 @@ const (
|
|||||||
PB30 Pin = 62
|
PB30 Pin = 62
|
||||||
PB31 Pin = 63
|
PB31 Pin = 63
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ const (
|
|||||||
BUTTON = PB31
|
BUTTON = PB31
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// https://ww1.microchip.com/downloads/en/DeviceDoc/70005321A.pdf
|
// https://ww1.microchip.com/downloads/en/DeviceDoc/70005321A.pdf
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const (
|
|||||||
BUTTON = PA0
|
BUTTON = PA0
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART1
|
var DefaultUART = UART1
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -57,8 +57,6 @@ const (
|
|||||||
UART_RX_PIN = P0_30 // PORTB
|
UART_RX_PIN = P0_30 // PORTB
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = P0_05 // I2C0 external
|
SDA_PIN = P0_05 // I2C0 external
|
||||||
|
|||||||
@@ -104,11 +104,6 @@ const (
|
|||||||
UART_TX_PIN = D1
|
UART_TX_PIN = D1
|
||||||
)
|
)
|
||||||
|
|
||||||
// Serial is the USB device
|
|
||||||
var (
|
|
||||||
Serial = USB
|
|
||||||
)
|
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = D20 // I2C0 external
|
SDA_PIN = D20 // I2C0 external
|
||||||
|
|||||||
@@ -68,8 +68,6 @@ const (
|
|||||||
ADC3 Pin = IO39
|
ADC3 Pin = IO39
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
|
||||||
|
|
||||||
// UART0 pins
|
// UART0 pins
|
||||||
const (
|
const (
|
||||||
UART_TX_PIN = IO1
|
UART_TX_PIN = IO1
|
||||||
|
|||||||
@@ -47,8 +47,6 @@ const (
|
|||||||
WS2812 = D8
|
WS2812 = D8
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// USBCDC pins
|
// USBCDC pins
|
||||||
const (
|
const (
|
||||||
USBCDC_DM_PIN = PA24
|
USBCDC_DM_PIN = PA24
|
||||||
|
|||||||
@@ -40,8 +40,6 @@ const (
|
|||||||
WS2812 = D8
|
WS2812 = D8
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// USBCDC pins
|
// USBCDC pins
|
||||||
const (
|
const (
|
||||||
USBCDC_DM_PIN = PA24
|
USBCDC_DM_PIN = PA24
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
// +build feather_nrf52840_sense
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
const HasLowFrequencyCrystal = true
|
||||||
|
|
||||||
|
// GPIO Pins
|
||||||
|
const (
|
||||||
|
D0 = P0_25 // UART TX
|
||||||
|
D1 = P0_24 // UART RX
|
||||||
|
D2 = P0_10 // NFC2
|
||||||
|
D3 = P1_11
|
||||||
|
D4 = P1_10 // LED2
|
||||||
|
D5 = P1_08
|
||||||
|
D6 = P0_07
|
||||||
|
D7 = P1_02 // Button
|
||||||
|
D8 = P0_16 // NeoPixel
|
||||||
|
D9 = P0_26
|
||||||
|
D10 = P0_27
|
||||||
|
D11 = P0_06
|
||||||
|
D12 = P0_08
|
||||||
|
D13 = P1_09 // LED1
|
||||||
|
D14 = P0_04 // A0
|
||||||
|
D15 = P0_05 // A1
|
||||||
|
D16 = P0_30 // A2
|
||||||
|
D17 = P0_28 // A3
|
||||||
|
D18 = P0_02 // A4
|
||||||
|
D19 = P0_03 // A5
|
||||||
|
D20 = P0_29 // Battery
|
||||||
|
D21 = P0_31 // AREF
|
||||||
|
D22 = P0_12 // I2C SDA
|
||||||
|
D23 = P0_11 // I2C SCL
|
||||||
|
D24 = P0_15 // SPI MISO
|
||||||
|
D25 = P0_13 // SPI MOSI
|
||||||
|
D26 = P0_14 // SPI SCK
|
||||||
|
D27 = P0_19 // QSPI CLK
|
||||||
|
D28 = P0_20 // QSPI CS
|
||||||
|
D29 = P0_17 // QSPI Data 0
|
||||||
|
D30 = P0_22 // QSPI Data 1
|
||||||
|
D31 = P0_23 // QSPI Data 2
|
||||||
|
D32 = P0_21 // QSPI Data 3
|
||||||
|
D33 = P0_09 // NFC1 (test point on bottom of board)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Analog Pins
|
||||||
|
const (
|
||||||
|
A0 = D14
|
||||||
|
A1 = D15
|
||||||
|
A2 = D16
|
||||||
|
A3 = D17
|
||||||
|
A4 = D18
|
||||||
|
A5 = D19
|
||||||
|
A6 = D20 // Battery
|
||||||
|
A7 = D21 // ARef
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
LED = D13
|
||||||
|
LED1 = LED
|
||||||
|
LED2 = D4
|
||||||
|
NEOPIXEL = D8
|
||||||
|
WS2812 = D8
|
||||||
|
BUTTON = D7
|
||||||
|
|
||||||
|
QSPI_SCK = D27
|
||||||
|
QSPI_CS = D28
|
||||||
|
QSPI_DATA0 = D29
|
||||||
|
QSPI_DATA1 = D30
|
||||||
|
QSPI_DATA2 = D31
|
||||||
|
QSPI_DATA3 = D32
|
||||||
|
)
|
||||||
|
|
||||||
|
// UART0 pins (logical UART1)
|
||||||
|
const (
|
||||||
|
UART_RX_PIN = D1
|
||||||
|
UART_TX_PIN = D0
|
||||||
|
)
|
||||||
|
|
||||||
|
// I2C pins
|
||||||
|
const (
|
||||||
|
SDA_PIN = D22 // I2C0 external
|
||||||
|
SCL_PIN = D23 // I2C0 external
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI pins
|
||||||
|
const (
|
||||||
|
SPI0_SCK_PIN = D26 // SCK
|
||||||
|
SPI0_SDO_PIN = D25 // SDO
|
||||||
|
SPI0_SDI_PIN = D24 // SDI
|
||||||
|
)
|
||||||
|
|
||||||
|
// USB CDC identifiers
|
||||||
|
const (
|
||||||
|
usb_STRING_PRODUCT = "Feather nRF52840 Express"
|
||||||
|
usb_STRING_MANUFACTURER = "Adafruit Industries LLC"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
usb_VID uint16 = 0x239A
|
||||||
|
usb_PID uint16 = 0x8088
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultUART = UART0
|
||||||
|
)
|
||||||
@@ -72,13 +72,8 @@ const (
|
|||||||
|
|
||||||
// UART0 pins (logical UART1)
|
// UART0 pins (logical UART1)
|
||||||
const (
|
const (
|
||||||
UART_RX_PIN = D0
|
UART_RX_PIN = D1
|
||||||
UART_TX_PIN = D1
|
UART_TX_PIN = D0
|
||||||
)
|
|
||||||
|
|
||||||
// Serial is the USB device
|
|
||||||
var (
|
|
||||||
Serial = USB
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
@@ -104,3 +99,7 @@ var (
|
|||||||
usb_VID uint16 = 0x239A
|
usb_VID uint16 = 0x239A
|
||||||
usb_PID uint16 = 0x802A
|
usb_PID uint16 = 0x802A
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
DefaultUART = UART0
|
||||||
|
)
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ var (
|
|||||||
TxAltFuncSelector: AF7_USART1_2_3,
|
TxAltFuncSelector: AF7_USART1_2_3,
|
||||||
RxAltFuncSelector: AF7_USART1_2_3,
|
RxAltFuncSelector: AF7_USART1_2_3,
|
||||||
}
|
}
|
||||||
Serial = UART1
|
DefaultUART = UART1
|
||||||
)
|
)
|
||||||
|
|
||||||
func initUART() {
|
func initUART() {
|
||||||
|
|||||||
@@ -8,3 +8,20 @@ const (
|
|||||||
// Onboard crystal oscillator frequency, in MHz.
|
// Onboard crystal oscillator frequency, in MHz.
|
||||||
xoscFreq = 12 // MHz
|
xoscFreq = 12 // MHz
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SPI default pins
|
||||||
|
const (
|
||||||
|
// Default Serial Clock Bus 0 for SPI communications
|
||||||
|
SPI0_SCK_PIN = GPIO18
|
||||||
|
// Default Serial Out Bus 0 for SPI communications
|
||||||
|
SPI0_SDO_PIN = GPIO19 // Tx
|
||||||
|
// Default Serial In Bus 0 for SPI communications
|
||||||
|
SPI0_SDI_PIN = GPIO20 // Rx
|
||||||
|
|
||||||
|
// Default Serial Clock Bus 1 for SPI communications
|
||||||
|
SPI1_SCK_PIN = GPIO10
|
||||||
|
// Default Serial Out Bus 1 for SPI communications
|
||||||
|
SPI1_SDO_PIN = GPIO11 // Tx
|
||||||
|
// Default Serial In Bus 1 for SPI communications
|
||||||
|
SPI1_SDI_PIN = GPIO12 // Rx
|
||||||
|
)
|
||||||
|
|||||||
@@ -142,8 +142,6 @@ const (
|
|||||||
WS2812 = NEOPIXEL_PIN
|
WS2812 = NEOPIXEL_PIN
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
UART1_RX_PIN = D0 // (PB25)
|
UART1_RX_PIN = D0 // (PB25)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ const (
|
|||||||
LED_BLUE = P21
|
LED_BLUE = P21
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// TODO: figure out the pin numbers for these.
|
// TODO: figure out the pin numbers for these.
|
||||||
|
|||||||
@@ -37,8 +37,6 @@ const (
|
|||||||
LED = D13
|
LED = D13
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// USBCDC pins
|
// USBCDC pins
|
||||||
const (
|
const (
|
||||||
USBCDC_DM_PIN = PA24
|
USBCDC_DM_PIN = PA24
|
||||||
|
|||||||
@@ -70,11 +70,6 @@ const (
|
|||||||
UART_TX_PIN = D1
|
UART_TX_PIN = D1
|
||||||
)
|
)
|
||||||
|
|
||||||
// Serial is the USB device
|
|
||||||
var (
|
|
||||||
Serial = USB
|
|
||||||
)
|
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = D21 // I2C0 external
|
SDA_PIN = D21 // I2C0 external
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ const (
|
|||||||
I2C0_SDA_PIN = PA10
|
I2C0_SDA_PIN = PA10
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ const (
|
|||||||
LED_BLUE = D14
|
LED_BLUE = D14
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
// Default pins for UARTHS.
|
// Default pins for UARTHS.
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -41,8 +41,6 @@ const (
|
|||||||
WS2812 = D40
|
WS2812 = D40
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// USBCDC pins
|
// USBCDC pins
|
||||||
const (
|
const (
|
||||||
USBCDC_DM_PIN = PA24
|
USBCDC_DM_PIN = PA24
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const (
|
|||||||
BUTTONB Pin = P11
|
BUTTONB Pin = P11
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const (
|
|||||||
BUTTONB Pin = 26
|
BUTTONB Pin = 26
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -70,11 +70,6 @@ const (
|
|||||||
UART_TX_PIN = P1_03
|
UART_TX_PIN = P1_03
|
||||||
)
|
)
|
||||||
|
|
||||||
// Serial is the USB device
|
|
||||||
var (
|
|
||||||
Serial = USB
|
|
||||||
)
|
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = P0_31
|
SDA_PIN = P0_31
|
||||||
|
|||||||
@@ -53,11 +53,16 @@ const (
|
|||||||
SCL_PIN Pin = GPIO13
|
SCL_PIN Pin = GPIO13
|
||||||
)
|
)
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins. SPI1 not available on Nano RP2040 Connect.
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN Pin = GPIO6
|
SPI0_SCK_PIN Pin = GPIO6
|
||||||
SPI0_SDO_PIN Pin = GPIO7
|
SPI0_SDO_PIN Pin = GPIO7
|
||||||
SPI0_SDI_PIN Pin = GPIO4
|
SPI0_SDI_PIN Pin = GPIO4
|
||||||
|
|
||||||
|
// GPIO22 does not have SPI functionality so we set it to avoid interfering with NINA.
|
||||||
|
SPI1_SCK_PIN Pin = GPIO22
|
||||||
|
SPI1_SDO_PIN Pin = GPIO22
|
||||||
|
SPI1_SDI_PIN Pin = GPIO22
|
||||||
)
|
)
|
||||||
|
|
||||||
// NINA-W102 Pins
|
// NINA-W102 Pins
|
||||||
|
|||||||
@@ -54,11 +54,6 @@ const (
|
|||||||
UART_TX_PIN = P0_08
|
UART_TX_PIN = P0_08
|
||||||
)
|
)
|
||||||
|
|
||||||
// Serial is the USB device
|
|
||||||
var (
|
|
||||||
Serial = USB
|
|
||||||
)
|
|
||||||
|
|
||||||
// I2C pins
|
// I2C pins
|
||||||
const (
|
const (
|
||||||
SDA_PIN = P0_17 // I2C0 external
|
SDA_PIN = P0_17 // I2C0 external
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ const (
|
|||||||
// Onboard blue LED (on the AI-Thinker module).
|
// Onboard blue LED (on the AI-Thinker module).
|
||||||
const LED = D4
|
const LED = D4
|
||||||
|
|
||||||
var Serial = UART0
|
|
||||||
|
|
||||||
// SPI pins
|
// SPI pins
|
||||||
const (
|
const (
|
||||||
SPI0_SCK_PIN = D5
|
SPI0_SCK_PIN = D5
|
||||||
|
|||||||
@@ -23,9 +23,6 @@ const (
|
|||||||
UART_RX_PIN Pin = NoPin
|
UART_RX_PIN Pin = NoPin
|
||||||
)
|
)
|
||||||
|
|
||||||
// Serial is the USB device
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// I2C pins (unused)
|
// I2C pins (unused)
|
||||||
const (
|
const (
|
||||||
SDA_PIN = NoPin
|
SDA_PIN = NoPin
|
||||||
|
|||||||
@@ -18,9 +18,6 @@ const (
|
|||||||
UART_RX_PIN Pin = 19
|
UART_RX_PIN Pin = 19
|
||||||
)
|
)
|
||||||
|
|
||||||
// Serial is the USB device
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// I2C pins (unused)
|
// I2C pins (unused)
|
||||||
const (
|
const (
|
||||||
SDA_PIN = NoPin
|
SDA_PIN = NoPin
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ var (
|
|||||||
Buffer: NewRingBuffer(),
|
Buffer: NewRingBuffer(),
|
||||||
Bus: stm32.USART2,
|
Bus: stm32.USART2,
|
||||||
}
|
}
|
||||||
Serial = UART2
|
DefaultUART = UART2
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ var (
|
|||||||
TxAltFuncSelector: UART_ALT_FN,
|
TxAltFuncSelector: UART_ALT_FN,
|
||||||
RxAltFuncSelector: UART_ALT_FN,
|
RxAltFuncSelector: UART_ALT_FN,
|
||||||
}
|
}
|
||||||
Serial = UART1
|
DefaultUART = UART1
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ var (
|
|||||||
TxAltFuncSelector: 4,
|
TxAltFuncSelector: 4,
|
||||||
RxAltFuncSelector: 4,
|
RxAltFuncSelector: 4,
|
||||||
}
|
}
|
||||||
Serial = UART1
|
DefaultUART = UART1
|
||||||
|
|
||||||
// I2C1 is documented, alias to I2C0 as well
|
// I2C1 is documented, alias to I2C0 as well
|
||||||
I2C1 = &I2C{
|
I2C1 = &I2C{
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ var (
|
|||||||
TxAltFuncSelector: 7,
|
TxAltFuncSelector: 7,
|
||||||
RxAltFuncSelector: 3,
|
RxAltFuncSelector: 3,
|
||||||
}
|
}
|
||||||
Serial = UART1
|
DefaultUART = UART1
|
||||||
|
|
||||||
// I2C1 is documented, alias to I2C0 as well
|
// I2C1 is documented, alias to I2C0 as well
|
||||||
I2C1 = &I2C{
|
I2C1 = &I2C{
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ var (
|
|||||||
TxAltFuncSelector: UART_ALT_FN,
|
TxAltFuncSelector: UART_ALT_FN,
|
||||||
RxAltFuncSelector: UART_ALT_FN,
|
RxAltFuncSelector: UART_ALT_FN,
|
||||||
}
|
}
|
||||||
Serial = UART1
|
DefaultUART = UART1
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const (
|
|||||||
|
|
||||||
// UART
|
// UART
|
||||||
var (
|
var (
|
||||||
Serial = UART0
|
DefaultUART = UART0
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const (
|
|||||||
|
|
||||||
// UART
|
// UART
|
||||||
var (
|
var (
|
||||||
Serial = UART0
|
DefaultUART = UART0
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ const (
|
|||||||
|
|
||||||
// UART
|
// UART
|
||||||
var (
|
var (
|
||||||
Serial = UART0
|
DefaultUART = UART0
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const (
|
|||||||
LED_BLUE Pin = 23
|
LED_BLUE Pin = 23
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const (
|
|||||||
BUTTON4 Pin = 16
|
BUTTON4 Pin = 16
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
// UART pins for NRF52840-DK
|
// UART pins for NRF52840-DK
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const (
|
|||||||
BUTTON4 Pin = 25
|
BUTTON4 Pin = 25
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -34,11 +34,6 @@ const (
|
|||||||
UART_RX_PIN Pin = NoPin
|
UART_RX_PIN Pin = NoPin
|
||||||
)
|
)
|
||||||
|
|
||||||
// Serial is the USB device
|
|
||||||
var (
|
|
||||||
Serial = USB
|
|
||||||
)
|
|
||||||
|
|
||||||
// I2C pins (unused)
|
// I2C pins (unused)
|
||||||
const (
|
const (
|
||||||
SDA_PIN = NoPin
|
SDA_PIN = NoPin
|
||||||
|
|||||||
@@ -37,3 +37,20 @@ const (
|
|||||||
// Onboard crystal oscillator frequency, in MHz.
|
// Onboard crystal oscillator frequency, in MHz.
|
||||||
xoscFreq = 12 // MHz
|
xoscFreq = 12 // MHz
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SPI default pins
|
||||||
|
const (
|
||||||
|
// Default Serial Clock Bus 0 for SPI communications
|
||||||
|
SPI0_SCK_PIN = GPIO18
|
||||||
|
// Default Serial Out Bus 0 for SPI communications
|
||||||
|
SPI0_SDO_PIN = GPIO19 // Tx
|
||||||
|
// Default Serial In Bus 0 for SPI communications
|
||||||
|
SPI0_SDI_PIN = GPIO16 // Rx
|
||||||
|
|
||||||
|
// Default Serial Clock Bus 1 for SPI communications
|
||||||
|
SPI1_SCK_PIN = GPIO10
|
||||||
|
// Default Serial Out Bus 1 for SPI communications
|
||||||
|
SPI1_SDO_PIN = GPIO11 // Tx
|
||||||
|
// Default Serial In Bus 1 for SPI communications
|
||||||
|
SPI1_SDI_PIN = GPIO12 // Rx
|
||||||
|
)
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const (
|
|||||||
LED3 = LCD_BACKLIGHT_LOW
|
LED3 = LCD_BACKLIGHT_LOW
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
// UART pins for PineTime. Note that RX is set to NoPin as RXD is not listed in
|
// UART pins for PineTime. Note that RX is set to NoPin as RXD is not listed in
|
||||||
// the PineTime schematic 1.0:
|
// the PineTime schematic 1.0:
|
||||||
|
|||||||
@@ -67,8 +67,6 @@ const (
|
|||||||
BUTTON_B_MASK = 128
|
BUTTON_B_MASK = 128
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// USBCDC pins
|
// USBCDC pins
|
||||||
const (
|
const (
|
||||||
USBCDC_DM_PIN = PA24
|
USBCDC_DM_PIN = PA24
|
||||||
|
|||||||
@@ -70,8 +70,6 @@ const (
|
|||||||
BUTTON_B_MASK = 128
|
BUTTON_B_MASK = 128
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// USBCDC pins
|
// USBCDC pins
|
||||||
const (
|
const (
|
||||||
USBCDC_DM_PIN = PA24
|
USBCDC_DM_PIN = PA24
|
||||||
|
|||||||
@@ -95,8 +95,6 @@ const (
|
|||||||
LED = D13
|
LED = D13
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// USBCDC pins
|
// USBCDC pins
|
||||||
const (
|
const (
|
||||||
USBCDC_DM_PIN = PA24
|
USBCDC_DM_PIN = PA24
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const (
|
|||||||
BUTTON Pin = 7
|
BUTTON Pin = 7
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
// UART pins
|
// UART pins
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ var (
|
|||||||
TxAltFuncSelector: AF7_USART1_2_3,
|
TxAltFuncSelector: AF7_USART1_2_3,
|
||||||
RxAltFuncSelector: AF7_USART1_2_3,
|
RxAltFuncSelector: AF7_USART1_2_3,
|
||||||
}
|
}
|
||||||
Serial = UART1
|
DefaultUART = UART1
|
||||||
)
|
)
|
||||||
|
|
||||||
// set up RX IRQ handler. Follow similar pattern for other UARTx instances
|
// set up RX IRQ handler. Follow similar pattern for other UARTx instances
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ var (
|
|||||||
TeensyUART5 = UART4
|
TeensyUART5 = UART4
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var DefaultUART = UART0
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultUART0RX = D00
|
defaultUART0RX = D00
|
||||||
defaultUART0TX = D01
|
defaultUART0TX = D01
|
||||||
|
|||||||
@@ -136,9 +136,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
Serial = UART1
|
DefaultUART = UART1
|
||||||
UART1 = &_UART1
|
UART1 = &_UART1
|
||||||
_UART1 = UART{
|
_UART1 = UART{
|
||||||
Bus: nxp.LPUART6,
|
Bus: nxp.LPUART6,
|
||||||
Buffer: NewRingBuffer(),
|
Buffer: NewRingBuffer(),
|
||||||
txBuffer: NewRingBuffer(),
|
txBuffer: NewRingBuffer(),
|
||||||
|
|||||||
@@ -325,8 +325,6 @@ const (
|
|||||||
OUTPUT_CTR_3V3 = PC15
|
OUTPUT_CTR_3V3 = PC15
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = USB
|
|
||||||
|
|
||||||
// USBCDC pins
|
// USBCDC pins
|
||||||
const (
|
const (
|
||||||
USBCDC_DM_PIN = PIN_USB_DM
|
USBCDC_DM_PIN = PIN_USB_DM
|
||||||
|
|||||||
@@ -27,4 +27,4 @@ const (
|
|||||||
|
|
||||||
const HasLowFrequencyCrystal = true
|
const HasLowFrequencyCrystal = true
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ func (i2c *I2C) readByte() byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Always use UART0 as the serial output.
|
// Always use UART0 as the serial output.
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
// UART
|
// UART
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -251,6 +251,8 @@ func (p Pin) mux() *volatile.Register32 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var DefaultUART = UART0
|
||||||
|
|
||||||
var (
|
var (
|
||||||
UART0 = &_UART0
|
UART0 = &_UART0
|
||||||
_UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()}
|
_UART0 = UART{Bus: esp.UART0, Buffer: NewRingBuffer()}
|
||||||
|
|||||||
@@ -139,6 +139,8 @@ func (p Pin) PortMaskClear() (*uint32, uint32) {
|
|||||||
return &esp.GPIO.GPIO_OUT_W1TC.Reg, 1 << p
|
return &esp.GPIO.GPIO_OUT_W1TC.Reg, 1 << p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var DefaultUART = UART0
|
||||||
|
|
||||||
// UART0 is a hardware UART that supports both TX and RX.
|
// UART0 is a hardware UART that supports both TX and RX.
|
||||||
var UART0 = &_UART0
|
var UART0 = &_UART0
|
||||||
var _UART0 = UART{Buffer: NewRingBuffer()}
|
var _UART0 = UART{Buffer: NewRingBuffer()}
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ var (
|
|||||||
USB = &UART{100}
|
USB = &UART{100}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// The Serial port always points to the default UART in a simulated environment.
|
||||||
|
//
|
||||||
|
// TODO: perhaps this should be a special serial object that outputs via WASI
|
||||||
|
// stdout calls.
|
||||||
|
var Serial = UART0
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PinInput PinMode = iota
|
PinInput PinMode = iota
|
||||||
PinOutput
|
PinOutput
|
||||||
@@ -118,12 +124,6 @@ type UART struct {
|
|||||||
Bus uint8
|
Bus uint8
|
||||||
}
|
}
|
||||||
|
|
||||||
type UARTConfig struct {
|
|
||||||
BaudRate uint32
|
|
||||||
TX Pin
|
|
||||||
RX Pin
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configure the UART.
|
// Configure the UART.
|
||||||
func (uart *UART) Configure(config UARTConfig) {
|
func (uart *UART) Configure(config UARTConfig) {
|
||||||
uartConfigure(uart.Bus, config.TX, config.RX)
|
uartConfigure(uart.Bus, config.TX, config.RX)
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var Serial = UART0
|
var DefaultUART = UART0
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
UART0.Interrupt = interrupt.New(rp.IRQ_UART0_IRQ, _UART0.handleInterrupt)
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ const (
|
|||||||
PinInputPullup
|
PinInputPullup
|
||||||
PinAnalog
|
PinAnalog
|
||||||
PinUART
|
PinUART
|
||||||
|
PinSPI
|
||||||
)
|
)
|
||||||
|
|
||||||
// set drives the pin high
|
// set drives the pin high
|
||||||
@@ -155,6 +156,8 @@ func (p Pin) Configure(config PinConfig) {
|
|||||||
p.pulloff()
|
p.pulloff()
|
||||||
case PinUART:
|
case PinUART:
|
||||||
p.setFunc(fnUART)
|
p.setFunc(fnUART)
|
||||||
|
case PinSPI:
|
||||||
|
p.setFunc(fnSPI)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,361 @@
|
|||||||
|
// +build rp2040
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"device/rp"
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPI on the RP2040
|
||||||
|
var (
|
||||||
|
SPI0 = &_SPI0
|
||||||
|
_SPI0 = SPI{
|
||||||
|
Bus: rp.SPI0,
|
||||||
|
}
|
||||||
|
SPI1 = &_SPI1
|
||||||
|
_SPI1 = SPI{
|
||||||
|
Bus: rp.SPI1,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// SPIConfig is used to store config info for SPI.
|
||||||
|
type SPIConfig struct {
|
||||||
|
Frequency uint32
|
||||||
|
// LSB not supported on rp2040.
|
||||||
|
LSBFirst bool
|
||||||
|
// Mode's two most LSB are CPOL and CPHA. i.e. Mode==2 (0b10) is CPOL=1, CPHA=0
|
||||||
|
Mode uint8
|
||||||
|
// Number of data bits per transfer. Valid values 4..16. Default and recommended is 8.
|
||||||
|
DataBits uint8
|
||||||
|
// Serial clock pin
|
||||||
|
SCK Pin
|
||||||
|
// TX or Serial Data Out (MOSI if rp2040 is master)
|
||||||
|
SDO Pin
|
||||||
|
// RX or Serial Data In (MISO if rp2040 is master)
|
||||||
|
SDI Pin
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrLSBNotSupported = errors.New("SPI LSB unsupported on PL022")
|
||||||
|
ErrTxInvalidSliceSize = errors.New("SPI write and read slices must be same size")
|
||||||
|
ErrSPITimeout = errors.New("SPI timeout")
|
||||||
|
ErrSPIBaud = errors.New("SPI baud too low or above 66.5Mhz")
|
||||||
|
)
|
||||||
|
|
||||||
|
type SPI struct {
|
||||||
|
Bus *rp.SPI0_Type
|
||||||
|
}
|
||||||
|
|
||||||
|
// time to wait on a transaction before dropping. Unit in Microseconds for compatibility with ticks().
|
||||||
|
const _SPITimeout = 10 * 1000 // 10 ms
|
||||||
|
|
||||||
|
// Tx handles read/write operation for SPI interface. Since SPI is a syncronous write/read
|
||||||
|
// interface, there must always be the same number of bytes written as bytes read.
|
||||||
|
// The Tx method knows about this, and offers a few different ways of calling it.
|
||||||
|
//
|
||||||
|
// This form sends the bytes in tx buffer, putting the resulting bytes read into the rx buffer.
|
||||||
|
// Note that the tx and rx buffers must be the same size:
|
||||||
|
//
|
||||||
|
// spi.Tx(tx, rx)
|
||||||
|
//
|
||||||
|
// This form sends the tx buffer, ignoring the result. Useful for sending "commands" that return zeros
|
||||||
|
// until all the bytes in the command packet have been received:
|
||||||
|
//
|
||||||
|
// spi.Tx(tx, nil)
|
||||||
|
//
|
||||||
|
// This form sends zeros, putting the result into the rx buffer. Good for reading a "result packet":
|
||||||
|
//
|
||||||
|
// spi.Tx(nil, rx)
|
||||||
|
//
|
||||||
|
// Remark: This implementation (RP2040) allows reading into buffer with a custom repeated
|
||||||
|
// value on tx.
|
||||||
|
//
|
||||||
|
// spi.Tx([]byte{0xff}, rx) // may cause unwanted heap allocations.
|
||||||
|
//
|
||||||
|
// This form sends 0xff and puts the result into rx buffer. Useful for reading from SD cards
|
||||||
|
// which require 0xff input on SI.
|
||||||
|
func (spi SPI) Tx(w, r []byte) (err error) {
|
||||||
|
switch {
|
||||||
|
case w == nil:
|
||||||
|
// read only, so write zero and read a result.
|
||||||
|
err = spi.rx(r, 0)
|
||||||
|
case r == nil:
|
||||||
|
// write only
|
||||||
|
err = spi.tx(w)
|
||||||
|
case len(w) == 1 && len(r) > 1:
|
||||||
|
// Read with custom repeated value.
|
||||||
|
err = spi.rx(r, w[0])
|
||||||
|
default:
|
||||||
|
// write/read
|
||||||
|
err = spi.txrx(w, r)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write a single byte and read a single byte from TX/RX FIFO.
|
||||||
|
func (spi SPI) Transfer(w byte) (byte, error) {
|
||||||
|
var deadline = ticks() + _SPITimeout
|
||||||
|
for !spi.isWritable() {
|
||||||
|
if ticks() > deadline {
|
||||||
|
return 0, ErrSPITimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
spi.Bus.SSPDR.Set(uint32(w))
|
||||||
|
|
||||||
|
for !spi.isReadable() {
|
||||||
|
if ticks() > deadline {
|
||||||
|
return 0, ErrSPITimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return uint8(spi.Bus.SSPDR.Get()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (spi SPI) SetBaudRate(br uint32) error {
|
||||||
|
const freqin uint32 = 125 * MHz
|
||||||
|
const maxBaud uint32 = 66.5 * MHz // max output frequency is 66.5MHz on rp2040. see Note page 527.
|
||||||
|
// Find smallest prescale value which puts output frequency in range of
|
||||||
|
// post-divide. Prescale is an even number from 2 to 254 inclusive.
|
||||||
|
var prescale, postdiv uint32
|
||||||
|
for prescale = 2; prescale < 255; prescale += 2 {
|
||||||
|
if freqin < (prescale+2)*256*br {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if prescale > 254 || br > maxBaud {
|
||||||
|
return ErrSPIBaud
|
||||||
|
}
|
||||||
|
// Find largest post-divide which makes output <= baudrate. Post-divide is
|
||||||
|
// an integer in the range 1 to 256 inclusive.
|
||||||
|
for postdiv = 256; postdiv > 1; postdiv-- {
|
||||||
|
if freqin/(prescale*(postdiv-1)) > br {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spi.Bus.SSPCPSR.Set(prescale)
|
||||||
|
spi.Bus.SSPCR0.ReplaceBits((postdiv-1)<<rp.SPI0_SSPCR0_SCR_Pos, rp.SPI0_SSPCR0_SCR_Msk, 0)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (spi SPI) GetBaudRate() uint32 {
|
||||||
|
const freqin uint32 = 125 * MHz
|
||||||
|
prescale := spi.Bus.SSPCPSR.Get()
|
||||||
|
postdiv := ((spi.Bus.SSPCR0.Get() & rp.SPI0_SSPCR0_SCR_Msk) >> rp.SPI0_SSPCR0_SCR_Pos) + 1
|
||||||
|
return freqin / (prescale * postdiv)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure is intended to setup/initialize the SPI interface.
|
||||||
|
// Default baudrate of 115200 is used if Frequency == 0. Default
|
||||||
|
// word length (data bits) is 8.
|
||||||
|
// Below is a list of GPIO pins corresponding to SPI0 bus on the rp2040:
|
||||||
|
// SI : 0, 4, 17 a.k.a RX and MISO (if rp2040 is master)
|
||||||
|
// SO : 3, 7, 19 a.k.a TX and MOSI (if rp2040 is master)
|
||||||
|
// SCK: 2, 6, 18
|
||||||
|
// SPI1 bus GPIO pins:
|
||||||
|
// SI : 8, 12
|
||||||
|
// SO : 11, 15
|
||||||
|
// SCK: 10, 14
|
||||||
|
// No pin configuration is needed of SCK, SDO and SDI needed after calling Configure.
|
||||||
|
func (spi SPI) Configure(config SPIConfig) error {
|
||||||
|
const defaultBaud uint32 = 115200
|
||||||
|
if config.SCK == 0 {
|
||||||
|
// set default pins if config zero valued or invalid clock pin supplied.
|
||||||
|
switch spi.Bus {
|
||||||
|
case rp.SPI0:
|
||||||
|
config.SCK = SPI0_SCK_PIN
|
||||||
|
config.SDO = SPI0_SDO_PIN
|
||||||
|
config.SDI = SPI0_SDI_PIN
|
||||||
|
case rp.SPI1:
|
||||||
|
config.SCK = SPI1_SCK_PIN
|
||||||
|
config.SDO = SPI1_SDO_PIN
|
||||||
|
config.SDI = SPI1_SDI_PIN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if config.DataBits < 4 || config.DataBits > 16 {
|
||||||
|
config.DataBits = 8
|
||||||
|
}
|
||||||
|
if config.Frequency == 0 {
|
||||||
|
config.Frequency = defaultBaud
|
||||||
|
}
|
||||||
|
// SPI pin configuration
|
||||||
|
config.SCK.setFunc(fnSPI)
|
||||||
|
config.SDO.setFunc(fnSPI)
|
||||||
|
config.SDI.setFunc(fnSPI)
|
||||||
|
|
||||||
|
return spi.initSPI(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (spi SPI) initSPI(config SPIConfig) (err error) {
|
||||||
|
spi.reset()
|
||||||
|
// LSB-first not supported on PL022:
|
||||||
|
if config.LSBFirst {
|
||||||
|
return ErrLSBNotSupported
|
||||||
|
}
|
||||||
|
err = spi.SetBaudRate(config.Frequency)
|
||||||
|
// Set SPI Format (CPHA and CPOL) and frame format (default is Motorola)
|
||||||
|
spi.setFormat(config.DataBits, config.Mode, rp.XIP_SSI_CTRLR0_SPI_FRF_STD)
|
||||||
|
|
||||||
|
// Always enable DREQ signals -- harmless if DMA is not listening
|
||||||
|
spi.Bus.SSPDMACR.SetBits(rp.SPI0_SSPDMACR_TXDMAE | rp.SPI0_SSPDMACR_RXDMAE)
|
||||||
|
// Finally enable the SPI
|
||||||
|
spi.Bus.SSPCR1.SetBits(rp.SPI0_SSPCR1_SSE)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (spi SPI) setFormat(databits, mode uint8, frameFormat uint32) {
|
||||||
|
cpha := uint32(mode) & 1
|
||||||
|
cpol := uint32(mode>>1) & 1
|
||||||
|
spi.Bus.SSPCR0.ReplaceBits(
|
||||||
|
(cpha<<rp.SPI0_SSPCR0_SPH_Pos)|
|
||||||
|
(cpol<<rp.SPI0_SSPCR0_SPO_Pos)|
|
||||||
|
(uint32(databits-1)<<rp.SPI0_SSPCR0_DSS_Pos)| // Set databits (SPI word length). Valid inputs are 4-16.
|
||||||
|
(frameFormat&0b11)<<rp.SPI0_SSPCR0_FRF_Pos, // Frame format bits 4:5
|
||||||
|
rp.SPI0_SSPCR0_SPH_Msk|rp.SPI0_SSPCR0_SPO_Msk|rp.SPI0_SSPCR0_DSS_Msk|rp.SPI0_SSPCR0_FRF_Msk, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset resets SPI and waits until reset is done.
|
||||||
|
//go:inline
|
||||||
|
func (spi SPI) reset() {
|
||||||
|
resetVal := spi.deinit()
|
||||||
|
rp.RESETS.RESET.ClearBits(resetVal)
|
||||||
|
// Wait until reset is done.
|
||||||
|
for !rp.RESETS.RESET_DONE.HasBits(resetVal) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (spi SPI) deinit() (resetVal uint32) {
|
||||||
|
switch spi.Bus {
|
||||||
|
case rp.SPI0:
|
||||||
|
resetVal = rp.RESETS_RESET_SPI0
|
||||||
|
case rp.SPI1:
|
||||||
|
resetVal = rp.RESETS_RESET_SPI1
|
||||||
|
}
|
||||||
|
// Perform SPI reset.
|
||||||
|
rp.RESETS.RESET.SetBits(resetVal)
|
||||||
|
return resetVal
|
||||||
|
}
|
||||||
|
|
||||||
|
// isWritable returns false if no space is available to write. True if a write is possible
|
||||||
|
//go:inline
|
||||||
|
func (spi SPI) isWritable() bool {
|
||||||
|
return spi.Bus.SSPSR.HasBits(rp.SPI0_SSPSR_TNF)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isReadable returns true if a read is possible i.e. data is present
|
||||||
|
//go:inline
|
||||||
|
func (spi SPI) isReadable() bool {
|
||||||
|
return spi.Bus.SSPSR.HasBits(rp.SPI0_SSPSR_RNE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrintRegs prints SPI's peripheral common registries current values
|
||||||
|
func (spi SPI) PrintRegs() {
|
||||||
|
cr0 := spi.Bus.SSPCR0.Get()
|
||||||
|
cr1 := spi.Bus.SSPCR1.Get()
|
||||||
|
dmacr := spi.Bus.SSPDMACR.Get()
|
||||||
|
cpsr := spi.Bus.SSPCPSR.Get()
|
||||||
|
dr := spi.Bus.SSPDR.Get()
|
||||||
|
ris := spi.Bus.SSPRIS.Get()
|
||||||
|
println("CR0:", cr0)
|
||||||
|
println("CR1:", cr1)
|
||||||
|
println("DMACR:", dmacr)
|
||||||
|
println("CPSR:", cpsr)
|
||||||
|
println("DR:", dr)
|
||||||
|
println("RIS:", ris)
|
||||||
|
}
|
||||||
|
|
||||||
|
//go:inline
|
||||||
|
func (spi SPI) isBusy() bool {
|
||||||
|
return spi.Bus.SSPSR.HasBits(rp.SPI0_SSPSR_BSY)
|
||||||
|
}
|
||||||
|
|
||||||
|
// tx writes buffer to SPI ignoring Rx.
|
||||||
|
func (spi SPI) tx(tx []byte) error {
|
||||||
|
var deadline = ticks() + _SPITimeout
|
||||||
|
// Write to TX FIFO whilst ignoring RX, then clean up afterward. When RX
|
||||||
|
// is full, PL022 inhibits RX pushes, and sets a sticky flag on
|
||||||
|
// push-on-full, but continues shifting. Safe if SSPIMSC_RORIM is not set.
|
||||||
|
for i := range tx {
|
||||||
|
for !spi.isWritable() {
|
||||||
|
if ticks() > deadline {
|
||||||
|
return ErrSPITimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spi.Bus.SSPDR.Set(uint32(tx[i]))
|
||||||
|
}
|
||||||
|
// Drain RX FIFO, then wait for shifting to finish (which may be *after*
|
||||||
|
// TX FIFO drains), then drain RX FIFO again
|
||||||
|
for spi.isReadable() {
|
||||||
|
spi.Bus.SSPDR.Get()
|
||||||
|
}
|
||||||
|
for spi.isBusy() {
|
||||||
|
if ticks() > deadline {
|
||||||
|
return ErrSPITimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for spi.isReadable() {
|
||||||
|
spi.Bus.SSPDR.Get()
|
||||||
|
}
|
||||||
|
// Don't leave overrun flag set
|
||||||
|
spi.Bus.SSPICR.Set(rp.SPI0_SSPICR_RORIC)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// rx reads buffer to SPI ignoring x.
|
||||||
|
// txrepeat is output repeatedly on SO as data is read in from SI.
|
||||||
|
// Generally this can be 0, but some devices require a specific value here,
|
||||||
|
// e.g. SD cards expect 0xff
|
||||||
|
func (spi SPI) rx(rx []byte, txrepeat byte) error {
|
||||||
|
var deadline = ticks() + _SPITimeout
|
||||||
|
plen := len(rx)
|
||||||
|
const fifoDepth = 8 // see txrx
|
||||||
|
var rxleft, txleft = plen, plen
|
||||||
|
for txleft != 0 || rxleft != 0 {
|
||||||
|
if txleft != 0 && spi.isWritable() && rxleft < txleft+fifoDepth {
|
||||||
|
spi.Bus.SSPDR.Set(uint32(txrepeat))
|
||||||
|
txleft--
|
||||||
|
}
|
||||||
|
if rxleft != 0 && spi.isReadable() {
|
||||||
|
rx[plen-rxleft] = uint8(spi.Bus.SSPDR.Get())
|
||||||
|
rxleft--
|
||||||
|
continue // if reading succesfully in rx there is no need to check deadline.
|
||||||
|
}
|
||||||
|
if ticks() > deadline {
|
||||||
|
return ErrSPITimeout
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write len bytes from src to SPI. Simultaneously read len bytes from SPI to dst.
|
||||||
|
// Note this function is guaranteed to exit in a known amount of time (bits sent * time per bit)
|
||||||
|
func (spi SPI) txrx(tx, rx []byte) error {
|
||||||
|
var deadline = ticks() + _SPITimeout
|
||||||
|
plen := len(tx)
|
||||||
|
if plen != len(rx) {
|
||||||
|
return ErrTxInvalidSliceSize
|
||||||
|
}
|
||||||
|
// Never have more transfers in flight than will fit into the RX FIFO,
|
||||||
|
// else FIFO will overflow if this code is heavily interrupted.
|
||||||
|
const fifoDepth = 8
|
||||||
|
var rxleft, txleft = plen, plen
|
||||||
|
for (txleft != 0 || rxleft != 0) && ticks() <= deadline {
|
||||||
|
if txleft != 0 && spi.isWritable() && rxleft < txleft+fifoDepth {
|
||||||
|
spi.Bus.SSPDR.Set(uint32(tx[plen-txleft]))
|
||||||
|
txleft--
|
||||||
|
}
|
||||||
|
if rxleft != 0 && spi.isReadable() {
|
||||||
|
rx[plen-rxleft] = uint8(spi.Bus.SSPDR.Get())
|
||||||
|
rxleft--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if txleft != 0 || rxleft != 0 {
|
||||||
|
// Transaction ended early due to timeout
|
||||||
|
return ErrSPITimeout
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// +build baremetal,serial.none
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
// Serial is a null device: writes to it are ignored.
|
||||||
|
var Serial = NullSerial{}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// +build baremetal,serial.uart
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
// Serial is implemented via the default (usually the first) UART on the chip.
|
||||||
|
var Serial = DefaultUART
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
// +build baremetal,serial.usb
|
||||||
|
|
||||||
|
package machine
|
||||||
|
|
||||||
|
// Serial is implemented via USB (USB-CDC).
|
||||||
|
var Serial = USB
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package machine
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
var errNoByte = errors.New("machine: no byte read")
|
||||||
|
|
||||||
|
// UARTConfig is a struct with which a UART (or similar object) can be
|
||||||
|
// configured. The baud rate is usually respected, but TX and RX may be ignored
|
||||||
|
// depending on the chip and the type of object.
|
||||||
|
type UARTConfig struct {
|
||||||
|
BaudRate uint32
|
||||||
|
TX Pin
|
||||||
|
RX Pin
|
||||||
|
}
|
||||||
|
|
||||||
|
// NullSerial is a serial version of /dev/null (or null router): it drops
|
||||||
|
// everything that is written to it.
|
||||||
|
type NullSerial struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure does nothing: the null serial has no configuration.
|
||||||
|
func (ns NullSerial) Configure(config UARTConfig) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteByte is a no-op: the null serial doesn't write bytes.
|
||||||
|
func (ns NullSerial) WriteByte(b byte) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadByte always returns an error because there aren't any bytes to read.
|
||||||
|
func (ns NullSerial) ReadByte() (byte, error) {
|
||||||
|
return 0, errNoByte
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffered returns how many bytes are buffered in the UART. It always returns 0
|
||||||
|
// as there are no bytes to read.
|
||||||
|
func (ns NullSerial) Buffered() int {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write is a no-op: none of the data is being written and it will not return an
|
||||||
|
// error.
|
||||||
|
func (ns NullSerial) Write(p []byte) (n int, err error) {
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
@@ -23,12 +23,6 @@ const (
|
|||||||
ParityOdd UARTParity = 2
|
ParityOdd UARTParity = 2
|
||||||
)
|
)
|
||||||
|
|
||||||
type UARTConfig struct {
|
|
||||||
BaudRate uint32
|
|
||||||
TX Pin
|
|
||||||
RX Pin
|
|
||||||
}
|
|
||||||
|
|
||||||
// To implement the UART interface for a board, you must declare a concrete type as follows:
|
// To implement the UART interface for a board, you must declare a concrete type as follows:
|
||||||
//
|
//
|
||||||
// type UART struct {
|
// type UART struct {
|
||||||
|
|||||||
@@ -7,3 +7,81 @@
|
|||||||
package net
|
package net
|
||||||
|
|
||||||
const hexDigit = "0123456789abcdef"
|
const hexDigit = "0123456789abcdef"
|
||||||
|
|
||||||
|
// A HardwareAddr represents a physical hardware address.
|
||||||
|
type HardwareAddr []byte
|
||||||
|
|
||||||
|
func (a HardwareAddr) String() string {
|
||||||
|
if len(a) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
buf := make([]byte, 0, len(a)*3-1)
|
||||||
|
for i, b := range a {
|
||||||
|
if i > 0 {
|
||||||
|
buf = append(buf, ':')
|
||||||
|
}
|
||||||
|
buf = append(buf, hexDigit[b>>4])
|
||||||
|
buf = append(buf, hexDigit[b&0xF])
|
||||||
|
}
|
||||||
|
return string(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseMAC parses s as an IEEE 802 MAC-48, EUI-48, EUI-64, or a 20-octet
|
||||||
|
// IP over InfiniBand link-layer address using one of the following formats:
|
||||||
|
// 00:00:5e:00:53:01
|
||||||
|
// 02:00:5e:10:00:00:00:01
|
||||||
|
// 00:00:00:00:fe:80:00:00:00:00:00:00:02:00:5e:10:00:00:00:01
|
||||||
|
// 00-00-5e-00-53-01
|
||||||
|
// 02-00-5e-10-00-00-00-01
|
||||||
|
// 00-00-00-00-fe-80-00-00-00-00-00-00-02-00-5e-10-00-00-00-01
|
||||||
|
// 0000.5e00.5301
|
||||||
|
// 0200.5e10.0000.0001
|
||||||
|
// 0000.0000.fe80.0000.0000.0000.0200.5e10.0000.0001
|
||||||
|
func ParseMAC(s string) (hw HardwareAddr, err error) {
|
||||||
|
if len(s) < 14 {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
|
||||||
|
if s[2] == ':' || s[2] == '-' {
|
||||||
|
if (len(s)+1)%3 != 0 {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
n := (len(s) + 1) / 3
|
||||||
|
if n != 6 && n != 8 && n != 20 {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
hw = make(HardwareAddr, n)
|
||||||
|
for x, i := 0, 0; i < n; i++ {
|
||||||
|
var ok bool
|
||||||
|
if hw[i], ok = xtoi2(s[x:], s[2]); !ok {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
x += 3
|
||||||
|
}
|
||||||
|
} else if s[4] == '.' {
|
||||||
|
if (len(s)+1)%5 != 0 {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
n := 2 * (len(s) + 1) / 5
|
||||||
|
if n != 6 && n != 8 && n != 20 {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
hw = make(HardwareAddr, n)
|
||||||
|
for x, i := 0, 0; i < n; i += 2 {
|
||||||
|
var ok bool
|
||||||
|
if hw[i], ok = xtoi2(s[x:x+2], 0); !ok {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
if hw[i+1], ok = xtoi2(s[x+2:], s[4]); !ok {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
x += 5
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
goto err
|
||||||
|
}
|
||||||
|
return hw, nil
|
||||||
|
|
||||||
|
err:
|
||||||
|
return nil, &AddrError{Err: "invalid MAC address", Addr: s}
|
||||||
|
}
|
||||||
|
|||||||
@@ -52,6 +52,18 @@ func xtoi(s string) (n int, i int, ok bool) {
|
|||||||
return n, i, true
|
return n, i, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// xtoi2 converts the next two hex digits of s into a byte.
|
||||||
|
// If s is longer than 2 bytes then the third byte must be e.
|
||||||
|
// If the first two bytes of s are not hex digits or the third byte
|
||||||
|
// does not match e, false is returned.
|
||||||
|
func xtoi2(s string, e byte) (byte, bool) {
|
||||||
|
if len(s) > 2 && s[2] != e {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
n, ei, ok := xtoi(s[:2])
|
||||||
|
return byte(n), ok && ei == 2
|
||||||
|
}
|
||||||
|
|
||||||
// Convert unsigned integer to decimal string.
|
// Convert unsigned integer to decimal string.
|
||||||
func uitoa(val uint) string {
|
func uitoa(val uint) string {
|
||||||
if val == 0 { // avoid string allocation
|
if val == 0 { // avoid string allocation
|
||||||
|
|||||||
@@ -1,6 +1,18 @@
|
|||||||
package os
|
package os
|
||||||
|
|
||||||
|
import "syscall"
|
||||||
|
|
||||||
type Signal interface {
|
type Signal interface {
|
||||||
String() string
|
String() string
|
||||||
Signal() // to distinguish from other Stringers
|
Signal() // to distinguish from other Stringers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Getpid returns the process id of the caller, or -1 if unavailable.
|
||||||
|
func Getpid() int {
|
||||||
|
return syscall.Getpid()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getppid returns the process id of the caller's parent, or -1 if unavailable.
|
||||||
|
func Getppid() int {
|
||||||
|
return syscall.Getppid()
|
||||||
|
}
|
||||||
|
|||||||
@@ -196,8 +196,3 @@ func Readlink(name string) (string, error) {
|
|||||||
func TempDir() string {
|
func TempDir() string {
|
||||||
return "/tmp"
|
return "/tmp"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Getpid is a stub (for now), always returning 1
|
|
||||||
func Getpid() int {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -24,3 +24,31 @@ func runtime_args() []string // in package runtime
|
|||||||
func Exit(code int) {
|
func Exit(code int) {
|
||||||
syscall.Exit(code)
|
syscall.Exit(code)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Getuid returns the numeric user id of the caller.
|
||||||
|
//
|
||||||
|
// On non-POSIX systems, it returns -1.
|
||||||
|
func Getuid() int {
|
||||||
|
return syscall.Getuid()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Geteuid returns the numeric effective user id of the caller.
|
||||||
|
//
|
||||||
|
// On non-POSIX systems, it returns -1.
|
||||||
|
func Geteuid() int {
|
||||||
|
return syscall.Geteuid()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getgid returns the numeric group id of the caller.
|
||||||
|
//
|
||||||
|
// On non-POSIX systems, it returns -1.
|
||||||
|
func Getgid() int {
|
||||||
|
return syscall.Getgid()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getegid returns the numeric effective group id of the caller.
|
||||||
|
//
|
||||||
|
// On non-POSIX systems, it returns -1.
|
||||||
|
func Getegid() int {
|
||||||
|
return syscall.Getegid()
|
||||||
|
}
|
||||||
|
|||||||
@@ -32,9 +32,11 @@ var (
|
|||||||
|
|
||||||
const wasmPageSize = 64 * 1024
|
const wasmPageSize = 64 * 1024
|
||||||
|
|
||||||
// Align on word boundary.
|
|
||||||
func align(ptr uintptr) uintptr {
|
func align(ptr uintptr) uintptr {
|
||||||
return (ptr + 3) &^ 3
|
// Align to 16, which is the alignment of max_align_t:
|
||||||
|
// https://godbolt.org/z/dYqTsWrGq
|
||||||
|
const heapAlign = 16
|
||||||
|
return (ptr + heapAlign - 1) &^ (heapAlign - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCurrentStackPointer() uintptr
|
func getCurrentStackPointer() uintptr
|
||||||
@@ -55,3 +57,51 @@ func growHeap() bool {
|
|||||||
// Heap has grown successfully.
|
// Heap has grown successfully.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The below functions override the default allocator of wasi-libc.
|
||||||
|
// Most functions are defined but unimplemented to make sure that if there is
|
||||||
|
// any code using them, they will get an error instead of (incorrectly) using
|
||||||
|
// the wasi-libc dlmalloc heap implementation instead. If they are needed by any
|
||||||
|
// program, they can certainly be implemented.
|
||||||
|
|
||||||
|
//export malloc
|
||||||
|
func libc_malloc(size uintptr) unsafe.Pointer {
|
||||||
|
return alloc(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export free
|
||||||
|
func libc_free(ptr unsafe.Pointer) {
|
||||||
|
free(ptr)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export calloc
|
||||||
|
func libc_calloc(nmemb, size uintptr) unsafe.Pointer {
|
||||||
|
// Note: we could be even more correct here and check that nmemb * size
|
||||||
|
// doesn't overflow. However the current implementation should normally work
|
||||||
|
// fine.
|
||||||
|
return alloc(nmemb * size)
|
||||||
|
}
|
||||||
|
|
||||||
|
//export realloc
|
||||||
|
func libc_realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer {
|
||||||
|
runtimePanic("unimplemented: realloc")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export posix_memalign
|
||||||
|
func libc_posix_memalign(memptr *unsafe.Pointer, alignment, size uintptr) int {
|
||||||
|
runtimePanic("unimplemented: posix_memalign")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
//export aligned_alloc
|
||||||
|
func libc_aligned_alloc(alignment, bytes uintptr) unsafe.Pointer {
|
||||||
|
runtimePanic("unimplemented: aligned_alloc")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
//export malloc_usable_size
|
||||||
|
func libc_malloc_usable_size(ptr unsafe.Pointer) uintptr {
|
||||||
|
runtimePanic("unimplemented: malloc_usable_size")
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|||||||
@@ -52,3 +52,24 @@ func syscall_Exit(code int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const baremetal = true
|
const baremetal = true
|
||||||
|
|
||||||
|
// timeOffset is how long the monotonic clock started after the Unix epoch. It
|
||||||
|
// should be a positive integer under normal operation or zero when it has not
|
||||||
|
// been set.
|
||||||
|
var timeOffset int64
|
||||||
|
|
||||||
|
//go:linkname now time.now
|
||||||
|
func now() (sec int64, nsec int32, mono int64) {
|
||||||
|
mono = nanotime()
|
||||||
|
sec = (mono + timeOffset) / (1000 * 1000 * 1000)
|
||||||
|
nsec = int32((mono + timeOffset) - sec*(1000*1000*1000))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// AdjustTimeOffset adds the given offset to the built-in time offset. A
|
||||||
|
// positive value adds to the time (skipping some time), a negative value moves
|
||||||
|
// the clock into the past.
|
||||||
|
func AdjustTimeOffset(offset int64) {
|
||||||
|
// TODO: do this atomically?
|
||||||
|
timeOffset += offset
|
||||||
|
}
|
||||||
|
|||||||
@@ -228,6 +228,14 @@ func setHeapEnd(newHeapEnd uintptr) {
|
|||||||
// This function can be called again when the heap size increases. The caller is
|
// This function can be called again when the heap size increases. The caller is
|
||||||
// responsible for copying the metadata to the new location.
|
// responsible for copying the metadata to the new location.
|
||||||
func calculateHeapAddresses() {
|
func calculateHeapAddresses() {
|
||||||
|
if GOARCH == "wasm" {
|
||||||
|
// This is a workaround for a bug in wasm-ld: wasm-ld doesn't always
|
||||||
|
// align __heap_base and when this memory is shared through an API, it
|
||||||
|
// might result in unaligned memory. For details, see:
|
||||||
|
// https://reviews.llvm.org/D106499
|
||||||
|
// It should be removed once we switch to LLVM 13, where this is fixed.
|
||||||
|
heapStart = align(heapStart)
|
||||||
|
}
|
||||||
totalSize := heapEnd - heapStart
|
totalSize := heapEnd - heapStart
|
||||||
|
|
||||||
// Allocate some memory to keep 2 bits of information about every block.
|
// Allocate some memory to keep 2 bits of information about every block.
|
||||||
|
|||||||
@@ -11,3 +11,9 @@ const (
|
|||||||
flag_MAP_PRIVATE = 0x2
|
flag_MAP_PRIVATE = 0x2
|
||||||
flag_MAP_ANONYMOUS = 0x1000 // MAP_ANON
|
flag_MAP_ANONYMOUS = 0x1000 // MAP_ANON
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Source: https://opensource.apple.com/source/Libc/Libc-1439.100.3/include/time.h.auto.html
|
||||||
|
const (
|
||||||
|
clock_REALTIME = 0
|
||||||
|
clock_MONOTONIC_RAW = 4
|
||||||
|
)
|
||||||
|
|||||||
@@ -11,3 +11,9 @@ const (
|
|||||||
flag_MAP_PRIVATE = 0x2
|
flag_MAP_PRIVATE = 0x2
|
||||||
flag_MAP_ANONYMOUS = 0x20
|
flag_MAP_ANONYMOUS = 0x20
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Source: https://github.com/torvalds/linux/blob/master/include/uapi/linux/time.h
|
||||||
|
const (
|
||||||
|
clock_REALTIME = 0
|
||||||
|
clock_MONOTONIC_RAW = 4
|
||||||
|
)
|
||||||
|
|||||||
@@ -68,27 +68,6 @@ func nanotime() int64 {
|
|||||||
return ticksToNanoseconds(ticks())
|
return ticksToNanoseconds(ticks())
|
||||||
}
|
}
|
||||||
|
|
||||||
// timeOffset is how long the monotonic clock started after the Unix epoch. It
|
|
||||||
// should be a positive integer under normal operation or zero when it has not
|
|
||||||
// been set.
|
|
||||||
var timeOffset int64
|
|
||||||
|
|
||||||
//go:linkname now time.now
|
|
||||||
func now() (sec int64, nsec int32, mono int64) {
|
|
||||||
mono = nanotime()
|
|
||||||
sec = (mono + timeOffset) / (1000 * 1000 * 1000)
|
|
||||||
nsec = int32((mono + timeOffset) - sec*(1000*1000*1000))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdjustTimeOffset adds the given offset to the built-in time offset. A
|
|
||||||
// positive value adds to the time (skipping some time), a negative value moves
|
|
||||||
// the clock into the past.
|
|
||||||
func AdjustTimeOffset(offset int64) {
|
|
||||||
// TODO: do this atomically?
|
|
||||||
timeOffset += offset
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copied from the Go runtime source code.
|
// Copied from the Go runtime source code.
|
||||||
//go:linkname os_sigpipe os.sigpipe
|
//go:linkname os_sigpipe os.sigpipe
|
||||||
func os_sigpipe() {
|
func os_sigpipe() {
|
||||||
|
|||||||
@@ -50,6 +50,14 @@ func putchar(c byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:linkname now time.now
|
||||||
|
func now() (sec int64, nsec int32, mono int64) {
|
||||||
|
mono = nanotime()
|
||||||
|
sec = mono / (1000 * 1000 * 1000)
|
||||||
|
nsec = int32(mono - sec*(1000*1000*1000))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Abort executes the wasm 'unreachable' instruction.
|
// Abort executes the wasm 'unreachable' instruction.
|
||||||
func abort() {
|
func abort() {
|
||||||
trap()
|
trap()
|
||||||
|
|||||||
@@ -38,8 +38,6 @@ type timespec struct {
|
|||||||
tv_nsec int // long: on Linux and macOS, follows the platform bitness
|
tv_nsec int // long: on Linux and macOS, follows the platform bitness
|
||||||
}
|
}
|
||||||
|
|
||||||
const CLOCK_MONOTONIC_RAW = 4
|
|
||||||
|
|
||||||
var stackTop uintptr
|
var stackTop uintptr
|
||||||
|
|
||||||
func postinit() {}
|
func postinit() {}
|
||||||
@@ -138,19 +136,31 @@ func sleepTicks(d timeUnit) {
|
|||||||
usleep(uint(d) / 1000)
|
usleep(uint(d) / 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return monotonic time in nanoseconds.
|
func getTime(clock int32) uint64 {
|
||||||
//
|
|
||||||
// TODO: noescape
|
|
||||||
func monotime() uint64 {
|
|
||||||
ts := timespec{}
|
ts := timespec{}
|
||||||
clock_gettime(CLOCK_MONOTONIC_RAW, &ts)
|
clock_gettime(clock, &ts)
|
||||||
return uint64(ts.tv_sec)*1000*1000*1000 + uint64(ts.tv_nsec)
|
return uint64(ts.tv_sec)*1000*1000*1000 + uint64(ts.tv_nsec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Return monotonic time in nanoseconds.
|
||||||
|
func monotime() uint64 {
|
||||||
|
return getTime(clock_MONOTONIC_RAW)
|
||||||
|
}
|
||||||
|
|
||||||
func ticks() timeUnit {
|
func ticks() timeUnit {
|
||||||
return timeUnit(monotime())
|
return timeUnit(monotime())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//go:linkname now time.now
|
||||||
|
func now() (sec int64, nsec int32, mono int64) {
|
||||||
|
ts := timespec{}
|
||||||
|
clock_gettime(clock_REALTIME, &ts)
|
||||||
|
sec = int64(ts.tv_sec)
|
||||||
|
nsec = int32(ts.tv_nsec)
|
||||||
|
mono = nanotime()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
//go:linkname syscall_Exit syscall.Exit
|
//go:linkname syscall_Exit syscall.Exit
|
||||||
func syscall_Exit(code int) {
|
func syscall_Exit(code int) {
|
||||||
exit(code)
|
exit(code)
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// +build baremetal wasi wasm
|
||||||
|
|
||||||
|
// This file emulates some process-related functions that are only available
|
||||||
|
// under a real operating system.
|
||||||
|
|
||||||
|
package syscall
|
||||||
|
|
||||||
|
func Getuid() int { return -1 }
|
||||||
|
func Geteuid() int { return -1 }
|
||||||
|
func Getgid() int { return -1 }
|
||||||
|
func Getegid() int { return -1 }
|
||||||
|
func Getpid() int { return -1 }
|
||||||
|
func Getppid() int { return -1 }
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user