This adds support for stdio in picolibc and fixes wasm_exec.js so that
it can also support C puts. With this, C stdout works on all supported
platforms.
There is no need to put these in the board files as the I2S is the same
on all Microchip SAM D21 chips. This simplifies the code and avoids some
special *_baremetal.go files.
This change does not change the resulting binaries.
This has practically no effect on the resulting binaries, the only
difference I could find was for the flash/console/spi driver example.
I'm not sure how to test that one, but I think it's very unlikely that
code will have changed in any meaningful way (apart from reordering some
globals).
This commit changes the I2C declarations so that the objects are
instantiated in each chip file (e.g. machine_atsamd21e18.go) and used to
define I2C0 (and similar) in the board file (e.g. board_qtpy.go). This
should make it easier to define new board files, and reduces the need
for separate *_baremetal.go files.
I have tested this the following way:
- With the LIS3DH driver example on the Circuit Playground Express and
the PyBadge.
- With the LSM6DS3 driver example on the Arduino Nano 33 IoT.
They both still work fine.
Instead of defining them separately for each board, define them once in
the chip definition and later simply use &sercomUART1 etc. to refer to
them. This is simpler and less error-prone.
I found two bugs while working on this:
- The P1AM-100 board mixed SERCOM 5 and SERCOM 3. It looks like SERCOM
5 was intended, based on the used pins.
- The Adafruit Matrix Portal appears to have configured the wrong
interrupt.
Unfortunately, I can't test these fixes. However, they make it clear
that such a change is important to avoid bugs.
I tested this commit on the PyBadge and the Circuit Playground Express.
This attribute is also set by Clang when it compiles C source files
(unless -fexceptions is set). The advantage is that no unwind tables are
emitted on Linux (and perhaps other systems). It also avoids
__aeabi_unwind_cpp_pr0 on ARM when using the musl libc.
This chip can run so much faster! Let's update the default frequency.
Also, change the UART implementation to be more fexible regarding the
clock frequency.
This commit changes `tinygo test` to always look at the exit code of the
running test, instead of looking for a "PASS" string at the end of the
output. This is possible now that the binaries running under
qemu-system-arm or qemu-system-riscv32 will signal the correct exit code
when they exit.
As a side effect, this also makes it possible to avoid the "PASS" line
between successful tests. Before:
$ tinygo test container/heap container/list
PASS
ok container/heap 0.001s
PASS
ok container/list 0.001s
After:
$ tinygo test container/heap container/list
ok container/heap 0.001s
ok container/list 0.001s
The new behavior is more in line with upstream Go:
go test container/heap container/list
ok container/heap 0.004s
ok container/list 0.004s
There were a few issues that were causing qemu-system-arm and
qemu-system-riscv to give the wrong exit codes. They are in fact capable
of exiting with 0 or 1 signalled from the running application, but this
functionality wasn't used. This commit changes this in the following
ways:
* It fixes SemiHosting codes, which were incorrectly written in
decimal while they should have been written in hexadecimal (oops!).
* It modifies all the baremetal main functions (aka reset handlers) to
exit with `exit(0)` instead of `abort()`.
* It changes `syscall.Exit` to call `exit(code)` instead of `abort()`
on baremetal targets.
* It adds these new exit functions where necessary, implemented in a
way that signals the correct exit status if running under QEMU.
All in all, this means that `tinygo test` doesn't have to look at the
output of a test to determine the outcome. It can simply look at the
exit code.
LLDB mostly works on most platforms, but it is still lacking in some
features. For example, it doesn't seem to support RISC-V yet (coming in
LLVM 12), it only partially supports AVR (no stacktraces), and it
doesn't seem to support the Ctrl-C keyboard command when running a
binary for another platform (e.g. with GOOS=arm64). However, it does
mostly work, even on baremetal systems.
Somehow this is accepted by QEMU. I'm doing this so that tests for
-target=hifive1-qemu still work with the RISC-V tasks scheduler (with a
stack size of 2048 bytes).
This is necessary to support the ESP32-C3, which lacks the A (atomic)
extension and thus requires these 32-bit atomic operations.
With this commit, flashing ./testdata/atomic.go to the ESP32-C3 works
correctly and produces the expected output on the serial console.
It is better to use environment variables (GOOS and GOARCH) for
consistency instead of providing two slightly incompatible ways. This
-target flag should only be used to specify a .json file (either
directly or in the TinyGo targets directory). Previously it was possible
to specify the LLVM target as well but that was never really fully
supported.
So:
- To specify a different OS/arch like you would in regular Go, use
GOOS and GOARCH.
- To specify a microcontroller chip or board, use the -target flag.
Also remove the old `os.Setenv` which might have had a purpose long ago
but doesn't have a purpose now.
... instead of setting a special -target= value. This is more robust and
makes sure that the test actually tests different arcitectures as they
would be compiled by TinyGo. As an example, the bug of the bugfix in the
previous commit ("arm: use armv7 instead of thumbv7") would have been
caught if this change was applied earlier.
I've decided to put GOOS/GOARCH in compileopts.Options, as it makes
sense to me to treat them the same way as command line parameters.
At the moment, thumbv7 is crashing. I'm not exactly sure why, but it
appears that there is an unknown instruction in __aeabi_uldivmod
(probably from libgcc).
I've fixed this by switching to armv7, which is also somewhat modern.
Maybe we can switch back to Thumb2 (aka thumbv7) once we start using
musl and compiler-rt. In the meantime, this does fix a miscompilation
(illegal instruction).
You can now debug the ESP32-C3 from the TinyGo command line, like this:
tinygo flash -target=esp32c3 examples/serial
tinygo gdb -target=esp32c3 examples/serial
It's important to flash before running `tinygo gdb`, because loading a
new firmware from GDB has not yet been implemented.
Probably the easiest way to connect to the ESP32-C3 is by using the
built-in JTAG connection. See:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-guides/jtag-debugging/configure-builtin-jtag.html
You will need to make sure that the `openocd` command in your $PATH is
the one from Espressif. Otherwise GDB will hang. You can debug this by
supplying the -ocd-output flag:
$ tinygo gdb -target=esp32c3 -ocd-output examples/serial
Open On-Chip Debugger 0.10.0
openocd: Licensed under GNU GPL v2
openocd: For bug reports, read
openocd: http://openocd.org/doc/doxygen/bugs.html
openocd: embedded:startup.tcl:60: Error: Can't find interface/esp_usb_jtag.cfg
openocd: in procedure 'script'
openocd: at file "embedded:startup.tcl", line 60
Make sure to configure OpenOCD correctly, until you get the correct
version (that includes the string "esp32"):
$ openocd --version
Open On-Chip Debugger v0.10.0-esp32-20210721 (2021-07-21-13:33)
Licensed under GNU GPL v2
For bug reports, read
http://openocd.org/doc/doxygen/bugs.html
If you are on Linux, you may also get the following error:
$ tinygo gdb -target=esp32c3 -ocd-output examples/serial
Open On-Chip Debugger v0.10.0-esp32-20210721 (2021-07-21-13:33)
openocd: Licensed under GNU GPL v2
openocd: For bug reports, read
openocd: http://openocd.org/doc/doxygen/bugs.html
openocd: Info : only one transport option; autoselect 'jtag'
openocd: adapter speed: 40000 kHz
openocd:
openocd: Warn : Transport "jtag" was already selected
openocd: Info : Listening on port 6666 for tcl connections
openocd: Info : Listening on port 4444 for telnet connections
openocd: Error: libusb_open() failed with LIBUSB_ERROR_ACCESS
openocd: Error: esp_usb_jtag: could not find or open device!
The error LIBUSB_ERROR_ACCESS means that there is a permission error.
You can fix this by creating the following file:
$ cat /etc/udev/rules.d/50-esp.rules
# ESP32-C3
SUBSYSTEMS=="usb", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="0666"
For more details, see:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32c3/api-guides/jtag-debugging/index.html
Hopefully this will fix the CI breakage after curl and wget refuse to
download anything from wasmtime.dev (which is signed by Let's Encrypt).
- wget needs and updated libgnutls30
- curl needs and updated libssl1.0.2
This is just a first step. It's not complete, but it gets some real
world C code to parse.
This signature, from the ESP-IDF:
esp_err_t esp_wifi_get_mac(wifi_interface_t ifx, uint8_t mac[6]);
Was previously converted to something like this (pseudocode):
C.esp_err_t esp_wifi_get_mac(ifx C.wifi_interface_t, mac [6]uint8)
But this is not correct. C array parameters will decay. The array is
passed by reference instead of by value. Instead, this would be the
correct signature:
C.esp_err_t esp_wifi_get_mac(ifx C.wifi_interface_t, mac *uint8)
So that it can be called like this (using CGo):
var mac [6]byte
errCode := C.esp_wifi_get_mac(C.ESP_IF_WIFI_AP, &mac[0])
This stores the result in the 6-element array mac.
For example, the following did not work before but does work with this
change:
// int add(int a, int b) {
// return a + b;
// }
import "C"
func main() {
println("add:", C.add(3, 5))
}
Even better, the functions in the header are compiled together with the
rest of the Go code and so they can be optimized together! Currently,
inlining is not yet allowed but const-propagation across functions
works. This should be improved in the future.
This commit changes a target triple like "armv6m-none-eabi" to
"armv6m-unknown-unknow-eabi". The reason is that while the former is
correctly parsed in Clang (due to normalization), it wasn't parsed
correctly in LLVM meaning that the environment wasn't set to EABI.
This change normalizes all target triples and uses the EABI environment
(-eabi in the triple) for Cortex-M targets.
This change also drops the `--target=` flag in the target JSON files,
the flag is now added implicitly in `(*compileopts.Config).CFlags()`.
This removes some duplication in target JSON files.
Unfortunately, this change also increases code size for Cortex-M
targets. It looks like LLVM now emits calls like __aeabi_memmove instead
of memmove, which pull in slightly more code (they basically just call
the regular C functions) and the calls themself don't seem to be as
efficient as they could be. Perhaps this is a LLVM bug that will be
fixed in the future, as this is a very common occurrence.
This brings some consistency to the CFlags and fixes the issue that on
some platforms (Linux, MacOS), no optimization level was set and
therefore C files in packages were not optimized at all.
This is a loose collection of small fixes flagged by staticcheck:
- dead code
- regexp expressions not using backticks (`foobar` / "foobar")
- redundant types of slice and map initializers
- misc other fixes
Not all of these seem very useful to me, but in particular dead code is
nice to fix. I've fixed them all just so that if there are problems,
they aren't hidden in the noise of less useful issues.