mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-20 20:39:06 +00:00
test: run ESP32 programs in QEMU
This commit is contained in:
@@ -196,6 +196,10 @@ jobs:
|
||||
cat /proc/cpuinfo
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends \
|
||||
libgcrypt20 \
|
||||
libpixman-1-0 \
|
||||
libsdl2-2.0-0 \
|
||||
libslirp0 \
|
||||
qemu-system-arm \
|
||||
qemu-system-riscv32 \
|
||||
qemu-user \
|
||||
@@ -216,6 +220,14 @@ jobs:
|
||||
version: "29.0.1"
|
||||
- name: Setup `wasm-tools`
|
||||
uses: bytecodealliance/actions/wasm-tools/setup@v1
|
||||
- name: Install Espressif QEMU
|
||||
run: |
|
||||
release=esp-develop-9.2.2-20260417
|
||||
archive=qemu-xtensa-softmmu-${release//-/_}-x86_64-linux-gnu.tar.xz
|
||||
curl -fL --retry 3 -o "$RUNNER_TEMP/$archive" \
|
||||
"https://github.com/espressif/qemu/releases/download/$release/$archive"
|
||||
tar -xJf "$RUNNER_TEMP/$archive" -C "$RUNNER_TEMP"
|
||||
echo "$RUNNER_TEMP/qemu/bin" >> "$GITHUB_PATH"
|
||||
- name: Restore LLVM source cache
|
||||
uses: actions/cache/restore@v5
|
||||
id: cache-llvm-source
|
||||
|
||||
@@ -261,6 +261,21 @@ func TestTimerStopResetRace(t *testing.T) {
|
||||
runTest("timer_stop_reset_race.go", optionsFromTarget("", sema), t, nil, nil)
|
||||
}
|
||||
|
||||
func TestESP32QEMU(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
options := optionsFromTarget("esp32-qemu", sema)
|
||||
emuCheck(t, options)
|
||||
machines, err := exec.Command("qemu-system-xtensa", "-machine", "help").Output()
|
||||
if err != nil {
|
||||
t.Fatal("failed to list qemu-system-xtensa machines:", err)
|
||||
}
|
||||
if !regexp.MustCompile(`(?m)^esp32\s`).Match(machines) {
|
||||
t.Skip("qemu-system-xtensa does not support the ESP32 machine")
|
||||
}
|
||||
runTest("print.go", options, t, nil, nil)
|
||||
}
|
||||
|
||||
func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||
emuCheck(t, options)
|
||||
|
||||
@@ -539,6 +554,9 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
if config.EmulatorName() == "simavr" {
|
||||
actual = cleanSimAVRTestOutput(actual)
|
||||
}
|
||||
if config.EmulatorName() == "qemu-system-xtensa" {
|
||||
actual = cleanESP32QEMUOutput(actual)
|
||||
}
|
||||
if name == "testing.go" {
|
||||
// Strip actual time.
|
||||
re := regexp.MustCompile(`\([0-9]\.[0-9][0-9]s\)`)
|
||||
@@ -564,6 +582,18 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
||||
}
|
||||
}
|
||||
|
||||
func cleanESP32QEMUOutput(output []byte) []byte {
|
||||
entryLine := bytes.Index(output, []byte("\nentry "))
|
||||
if entryLine < 0 {
|
||||
return output
|
||||
}
|
||||
entryLineEnd := bytes.IndexByte(output[entryLine+1:], '\n')
|
||||
if entryLineEnd < 0 {
|
||||
return output
|
||||
}
|
||||
return output[entryLine+1+entryLineEnd+1:]
|
||||
}
|
||||
|
||||
func cleanSimAVRTestOutput(output []byte) []byte {
|
||||
output = bytes.ReplaceAll(output, []byte{0x1b, '[', '3', '2', 'm'}, nil)
|
||||
output = bytes.ReplaceAll(output, []byte{0x1b, '[', '0', 'm'}, nil)
|
||||
|
||||
@@ -78,12 +78,6 @@ var _ebss [0]byte
|
||||
//go:extern _vector_table
|
||||
var _vector_table [0]uintptr
|
||||
|
||||
func abort() {
|
||||
for {
|
||||
device.Asm("waiti 0")
|
||||
}
|
||||
}
|
||||
|
||||
// interruptInit installs the Xtensa vector table by writing its address
|
||||
// to the VECBASE special register and ensures all CPU interrupts are
|
||||
// initially disabled.
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
//go:build esp32 && !qemu
|
||||
|
||||
package runtime
|
||||
|
||||
import "device"
|
||||
|
||||
func abort() {
|
||||
for {
|
||||
device.Asm("waiti 0")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//go:build esp32 && qemu
|
||||
|
||||
package runtime
|
||||
|
||||
import "device"
|
||||
|
||||
func exit(code int) {
|
||||
qemuExit(code)
|
||||
}
|
||||
|
||||
func abort() {
|
||||
qemuExit(1)
|
||||
}
|
||||
|
||||
func qemuExit(code int) {
|
||||
// QEMU semihosting expects a2 = SYS_exit (1) and a3 = the exit code.
|
||||
// AsmFull cannot declare these clobbers, so no Go code may run afterward.
|
||||
device.AsmFull(
|
||||
"mov a3, {code}\n"+
|
||||
"movi a2, 1\n"+
|
||||
"simcall",
|
||||
map[string]interface{}{"code": code},
|
||||
)
|
||||
// This loop ensures the clobbered registers are never used again.
|
||||
for {
|
||||
device.Asm("waiti 0")
|
||||
}
|
||||
}
|
||||
@@ -55,10 +55,6 @@ func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||
return int64(ticks) * 25
|
||||
}
|
||||
|
||||
func exit(code int) {
|
||||
abort()
|
||||
}
|
||||
|
||||
func putchar(c byte) {
|
||||
machine.Serial.WriteByte(c)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
//go:build (esp32 && !qemu) || esp32c3 || esp32c6
|
||||
|
||||
package runtime
|
||||
|
||||
func exit(code int) {
|
||||
abort()
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"inherits": ["esp32-generic"],
|
||||
"build-tags": ["qemu"],
|
||||
"emulator": "qemu-system-xtensa -machine esp32 -nographic -semihosting -drive file={img},if=mtd,format=raw"
|
||||
}
|
||||
@@ -25,6 +25,5 @@
|
||||
],
|
||||
"binary-format": "esp32",
|
||||
"flash-method": "esp32flash",
|
||||
"emulator": "qemu-system-xtensa -machine esp32 -nographic -drive file={img},if=mtd,format=raw",
|
||||
"gdb": ["xtensa-esp32-elf-gdb"]
|
||||
}
|
||||
|
||||
@@ -25,6 +25,5 @@
|
||||
],
|
||||
"binary-format": "esp32s3",
|
||||
"flash-method": "esp32jtag",
|
||||
"emulator": "qemu-system-xtensa -machine esp32 -nographic -drive file={img},if=mtd,format=raw",
|
||||
"gdb": ["xtensa-esp32-elf-gdb"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user