mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-21 04:49:04 +00:00
test: run ESP32 programs in QEMU
This commit is contained in:
@@ -196,6 +196,10 @@ jobs:
|
|||||||
cat /proc/cpuinfo
|
cat /proc/cpuinfo
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get install --no-install-recommends \
|
sudo apt-get install --no-install-recommends \
|
||||||
|
libgcrypt20 \
|
||||||
|
libpixman-1-0 \
|
||||||
|
libsdl2-2.0-0 \
|
||||||
|
libslirp0 \
|
||||||
qemu-system-arm \
|
qemu-system-arm \
|
||||||
qemu-system-riscv32 \
|
qemu-system-riscv32 \
|
||||||
qemu-user \
|
qemu-user \
|
||||||
@@ -216,6 +220,14 @@ jobs:
|
|||||||
version: "29.0.1"
|
version: "29.0.1"
|
||||||
- name: Setup `wasm-tools`
|
- name: Setup `wasm-tools`
|
||||||
uses: bytecodealliance/actions/wasm-tools/setup@v1
|
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
|
- name: Restore LLVM source cache
|
||||||
uses: actions/cache/restore@v5
|
uses: actions/cache/restore@v5
|
||||||
id: cache-llvm-source
|
id: cache-llvm-source
|
||||||
|
|||||||
@@ -261,6 +261,21 @@ func TestTimerStopResetRace(t *testing.T) {
|
|||||||
runTest("timer_stop_reset_race.go", optionsFromTarget("", sema), t, nil, nil)
|
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) {
|
func runPlatTests(options compileopts.Options, tests []string, t *testing.T) {
|
||||||
emuCheck(t, options)
|
emuCheck(t, options)
|
||||||
|
|
||||||
@@ -539,6 +554,9 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c
|
|||||||
if config.EmulatorName() == "simavr" {
|
if config.EmulatorName() == "simavr" {
|
||||||
actual = cleanSimAVRTestOutput(actual)
|
actual = cleanSimAVRTestOutput(actual)
|
||||||
}
|
}
|
||||||
|
if config.EmulatorName() == "qemu-system-xtensa" {
|
||||||
|
actual = cleanESP32QEMUOutput(actual)
|
||||||
|
}
|
||||||
if name == "testing.go" {
|
if name == "testing.go" {
|
||||||
// Strip actual time.
|
// Strip actual time.
|
||||||
re := regexp.MustCompile(`\([0-9]\.[0-9][0-9]s\)`)
|
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 {
|
func cleanSimAVRTestOutput(output []byte) []byte {
|
||||||
output = bytes.ReplaceAll(output, []byte{0x1b, '[', '3', '2', 'm'}, nil)
|
output = bytes.ReplaceAll(output, []byte{0x1b, '[', '3', '2', 'm'}, nil)
|
||||||
output = bytes.ReplaceAll(output, []byte{0x1b, '[', '0', 'm'}, nil)
|
output = bytes.ReplaceAll(output, []byte{0x1b, '[', '0', 'm'}, nil)
|
||||||
|
|||||||
@@ -78,12 +78,6 @@ var _ebss [0]byte
|
|||||||
//go:extern _vector_table
|
//go:extern _vector_table
|
||||||
var _vector_table [0]uintptr
|
var _vector_table [0]uintptr
|
||||||
|
|
||||||
func abort() {
|
|
||||||
for {
|
|
||||||
device.Asm("waiti 0")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// interruptInit installs the Xtensa vector table by writing its address
|
// interruptInit installs the Xtensa vector table by writing its address
|
||||||
// to the VECBASE special register and ensures all CPU interrupts are
|
// to the VECBASE special register and ensures all CPU interrupts are
|
||||||
// initially disabled.
|
// 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
|
return int64(ticks) * 25
|
||||||
}
|
}
|
||||||
|
|
||||||
func exit(code int) {
|
|
||||||
abort()
|
|
||||||
}
|
|
||||||
|
|
||||||
func putchar(c byte) {
|
func putchar(c byte) {
|
||||||
machine.Serial.WriteByte(c)
|
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",
|
"binary-format": "esp32",
|
||||||
"flash-method": "esp32flash",
|
"flash-method": "esp32flash",
|
||||||
"emulator": "qemu-system-xtensa -machine esp32 -nographic -drive file={img},if=mtd,format=raw",
|
|
||||||
"gdb": ["xtensa-esp32-elf-gdb"]
|
"gdb": ["xtensa-esp32-elf-gdb"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,5 @@
|
|||||||
],
|
],
|
||||||
"binary-format": "esp32s3",
|
"binary-format": "esp32s3",
|
||||||
"flash-method": "esp32jtag",
|
"flash-method": "esp32jtag",
|
||||||
"emulator": "qemu-system-xtensa -machine esp32 -nographic -drive file={img},if=mtd,format=raw",
|
|
||||||
"gdb": ["xtensa-esp32-elf-gdb"]
|
"gdb": ["xtensa-esp32-elf-gdb"]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user