Skip to content

Commit 1958d6f

Browse files
jakebaileydeadprogram
authored andcommitted
test: run ESP32 programs in QEMU
1 parent 1991b00 commit 1958d6f

10 files changed

Lines changed: 93 additions & 12 deletions

File tree

.github/workflows/linux.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,10 @@ jobs:
196196
cat /proc/cpuinfo
197197
sudo apt-get update
198198
sudo apt-get install --no-install-recommends \
199+
libgcrypt20 \
200+
libpixman-1-0 \
201+
libsdl2-2.0-0 \
202+
libslirp0 \
199203
qemu-system-arm \
200204
qemu-system-riscv32 \
201205
qemu-user \
@@ -216,6 +220,14 @@ jobs:
216220
version: "29.0.1"
217221
- name: Setup `wasm-tools`
218222
uses: bytecodealliance/actions/wasm-tools/setup@v1
223+
- name: Install Espressif QEMU
224+
run: |
225+
release=esp-develop-9.2.2-20260417
226+
archive=qemu-xtensa-softmmu-${release//-/_}-x86_64-linux-gnu.tar.xz
227+
curl -fL --retry 3 -o "$RUNNER_TEMP/$archive" \
228+
"https://github.com/espressif/qemu/releases/download/$release/$archive"
229+
tar -xJf "$RUNNER_TEMP/$archive" -C "$RUNNER_TEMP"
230+
echo "$RUNNER_TEMP/qemu/bin" >> "$GITHUB_PATH"
219231
- name: Restore LLVM source cache
220232
uses: actions/cache/restore@v5
221233
id: cache-llvm-source

main_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,21 @@ func TestTimerStopResetRace(t *testing.T) {
261261
runTest("timer_stop_reset_race.go", optionsFromTarget("", sema), t, nil, nil)
262262
}
263263

264+
func TestESP32QEMU(t *testing.T) {
265+
t.Parallel()
266+
267+
options := optionsFromTarget("esp32-qemu", sema)
268+
emuCheck(t, options)
269+
machines, err := exec.Command("qemu-system-xtensa", "-machine", "help").Output()
270+
if err != nil {
271+
t.Fatal("failed to list qemu-system-xtensa machines:", err)
272+
}
273+
if !regexp.MustCompile(`(?m)^esp32\s`).Match(machines) {
274+
t.Skip("qemu-system-xtensa does not support the ESP32 machine")
275+
}
276+
runTest("print.go", options, t, nil, nil)
277+
}
278+
264279
func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
265280
emuCheck(t, options)
266281

@@ -539,6 +554,9 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
539554
if config.EmulatorName() == "simavr" {
540555
actual = cleanSimAVRTestOutput(actual)
541556
}
557+
if config.EmulatorName() == "qemu-system-xtensa" {
558+
actual = cleanESP32QEMUOutput(actual)
559+
}
542560
if name == "testing.go" {
543561
// Strip actual time.
544562
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
564582
}
565583
}
566584

585+
func cleanESP32QEMUOutput(output []byte) []byte {
586+
entryLine := bytes.Index(output, []byte("\nentry "))
587+
if entryLine < 0 {
588+
return output
589+
}
590+
entryLineEnd := bytes.IndexByte(output[entryLine+1:], '\n')
591+
if entryLineEnd < 0 {
592+
return output
593+
}
594+
return output[entryLine+1+entryLineEnd+1:]
595+
}
596+
567597
func cleanSimAVRTestOutput(output []byte) []byte {
568598
output = bytes.ReplaceAll(output, []byte{0x1b, '[', '3', '2', 'm'}, nil)
569599
output = bytes.ReplaceAll(output, []byte{0x1b, '[', '0', 'm'}, nil)

src/runtime/runtime_esp32.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,12 +78,6 @@ var _ebss [0]byte
7878
//go:extern _vector_table
7979
var _vector_table [0]uintptr
8080

81-
func abort() {
82-
for {
83-
device.Asm("waiti 0")
84-
}
85-
}
86-
8781
// interruptInit installs the Xtensa vector table by writing its address
8882
// to the VECBASE special register and ensures all CPU interrupts are
8983
// initially disabled.

src/runtime/runtime_esp32_abort.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//go:build esp32 && !qemu
2+
3+
package runtime
4+
5+
import "device"
6+
7+
func abort() {
8+
for {
9+
device.Asm("waiti 0")
10+
}
11+
}

src/runtime/runtime_esp32_qemu.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//go:build esp32 && qemu
2+
3+
package runtime
4+
5+
import "device"
6+
7+
func exit(code int) {
8+
qemuExit(code)
9+
}
10+
11+
func abort() {
12+
qemuExit(1)
13+
}
14+
15+
func qemuExit(code int) {
16+
// QEMU semihosting expects a2 = SYS_exit (1) and a3 = the exit code.
17+
// AsmFull cannot declare these clobbers, so no Go code may run afterward.
18+
device.AsmFull(
19+
"mov a3, {code}\n"+
20+
"movi a2, 1\n"+
21+
"simcall",
22+
map[string]interface{}{"code": code},
23+
)
24+
// This loop ensures the clobbered registers are never used again.
25+
for {
26+
device.Asm("waiti 0")
27+
}
28+
}

src/runtime/runtime_esp32xx.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,6 @@ func ticksToNanoseconds(ticks timeUnit) int64 {
5555
return int64(ticks) * 25
5656
}
5757

58-
func exit(code int) {
59-
abort()
60-
}
61-
6258
func putchar(c byte) {
6359
machine.Serial.WriteByte(c)
6460
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
//go:build (esp32 && !qemu) || esp32c3 || esp32c6
2+
3+
package runtime
4+
5+
func exit(code int) {
6+
abort()
7+
}

targets/esp32-qemu.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"inherits": ["esp32-generic"],
3+
"build-tags": ["qemu"],
4+
"emulator": "qemu-system-xtensa -machine esp32 -nographic -semihosting -drive file={img},if=mtd,format=raw"
5+
}

targets/esp32.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,5 @@
2525
],
2626
"binary-format": "esp32",
2727
"flash-method": "esp32flash",
28-
"emulator": "qemu-system-xtensa -machine esp32 -nographic -drive file={img},if=mtd,format=raw",
2928
"gdb": ["xtensa-esp32-elf-gdb"]
3029
}

targets/esp32s3.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,5 @@
2525
],
2626
"binary-format": "esp32s3",
2727
"flash-method": "esp32jtag",
28-
"emulator": "qemu-system-xtensa -machine esp32 -nographic -drive file={img},if=mtd,format=raw",
2928
"gdb": ["xtensa-esp32-elf-gdb"]
3029
}

0 commit comments

Comments
 (0)